2011-03-30 14:56:31 -04:00
|
|
|
|
{- A "remote" that is just a filesystem directory.
|
2011-03-30 13:18:46 -04:00
|
|
|
|
-
|
|
|
|
|
- Copyright 2011 Joey Hess <joey@kitenet.net>
|
|
|
|
|
-
|
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Remote.Directory (remote) where
|
|
|
|
|
|
2011-04-16 18:22:52 -04:00
|
|
|
|
import qualified Data.ByteString.Lazy.Char8 as L
|
2011-03-30 13:18:46 -04:00
|
|
|
|
import qualified Data.Map as M
|
|
|
|
|
|
2011-10-05 16:02:51 -04:00
|
|
|
|
import Common.Annex
|
2011-10-03 22:24:57 -04:00
|
|
|
|
import Utility.CopyFile
|
2011-06-01 21:56:04 -04:00
|
|
|
|
import Types.Remote
|
2011-06-30 13:16:57 -04:00
|
|
|
|
import qualified Git
|
2011-03-30 14:32:08 -04:00
|
|
|
|
import Config
|
2011-09-23 18:13:24 -04:00
|
|
|
|
import Utility.FileMode
|
2011-08-16 20:49:54 -04:00
|
|
|
|
import Remote.Helper.Special
|
|
|
|
|
import Remote.Helper.Encryptable
|
2011-04-16 18:22:52 -04:00
|
|
|
|
import Crypto
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
|
|
|
|
remote :: RemoteType Annex
|
|
|
|
|
remote = RemoteType {
|
|
|
|
|
typename = "directory",
|
2011-03-30 14:00:54 -04:00
|
|
|
|
enumerate = findSpecialRemotes "directory",
|
2011-03-30 13:18:46 -04:00
|
|
|
|
generate = gen,
|
2011-03-30 14:00:54 -04:00
|
|
|
|
setup = directorySetup
|
2011-03-30 13:18:46 -04:00
|
|
|
|
}
|
|
|
|
|
|
2011-04-15 15:09:36 -04:00
|
|
|
|
gen :: Git.Repo -> UUID -> Maybe RemoteConfig -> Annex (Remote Annex)
|
2011-04-16 18:22:52 -04:00
|
|
|
|
gen r u c = do
|
2011-03-30 14:32:08 -04:00
|
|
|
|
dir <- getConfig r "directory" (error "missing directory")
|
2011-03-30 15:15:46 -04:00
|
|
|
|
cst <- remoteCost r cheapRemoteCost
|
2011-04-17 00:40:23 -04:00
|
|
|
|
return $ encryptableRemote c
|
2011-04-16 21:41:14 -04: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,
|
2011-09-18 20:11:39 -04:00
|
|
|
|
config = Nothing,
|
|
|
|
|
repo = r
|
2011-04-16 21:41:14 -04:00
|
|
|
|
}
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
2011-04-15 15:09:36 -04:00
|
|
|
|
directorySetup :: UUID -> RemoteConfig -> Annex RemoteConfig
|
2011-03-30 14:00:54 -04:00
|
|
|
|
directorySetup u c = do
|
2011-03-30 13:18:46 -04:00
|
|
|
|
-- verify configuration is sane
|
2011-07-15 12:47:14 -04:00
|
|
|
|
let dir = fromMaybe (error "Specify directory=") $
|
2011-05-15 02:49:43 -04:00
|
|
|
|
M.lookup "directory" c
|
2011-05-17 03:10:13 -04:00
|
|
|
|
liftIO $ doesDirectoryExist dir
|
2011-05-17 11:44:13 -04:00
|
|
|
|
>>! error $ "Directory does not exist: " ++ dir
|
2011-04-16 16:29:28 -04:00
|
|
|
|
c' <- encryptionSetup c
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
2011-03-30 14:32:08 -04:00
|
|
|
|
-- The directory is stored in git config, not in this remote's
|
|
|
|
|
-- persistant state, so it can vary between hosts.
|
2011-04-16 16:29:28 -04:00
|
|
|
|
gitConfigSpecialRemote u c' "directory" dir
|
|
|
|
|
return $ M.delete "directory" c'
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
2011-11-28 23:20:31 -04:00
|
|
|
|
{- Locations to try to access a given Key in the Directory. -}
|
2011-11-22 18:20:55 -04:00
|
|
|
|
locations :: FilePath -> Key -> [FilePath]
|
2011-12-02 14:56:48 -04:00
|
|
|
|
locations d k = map (d </>) (keyPaths k)
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
2011-11-22 18:20:55 -04: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-16 21:41:14 -04:00
|
|
|
|
store :: FilePath -> Key -> Annex Bool
|
|
|
|
|
store d k = do
|
2011-11-28 22:43:51 -04:00
|
|
|
|
src <- inRepo $ gitAnnexLocation k
|
2011-11-22 18:20:55 -04:00
|
|
|
|
liftIO $ catchBoolIO $ storeHelper d k $ copyFileExternal src
|
2011-04-16 21:41:14 -04:00
|
|
|
|
|
|
|
|
|
storeEncrypted :: FilePath -> (Cipher, Key) -> Key -> Annex Bool
|
|
|
|
|
storeEncrypted d (cipher, enck) k = do
|
2011-11-28 22:43:51 -04:00
|
|
|
|
src <- inRepo $ gitAnnexLocation k
|
2011-11-22 18:20:55 -04:00
|
|
|
|
liftIO $ catchBoolIO $ storeHelper d enck $ encrypt src
|
2011-03-30 14:56:31 -04:00
|
|
|
|
where
|
2011-04-16 21:41:14 -04:00
|
|
|
|
encrypt src dest = do
|
2011-04-19 15:26:50 -04:00
|
|
|
|
withEncryptedContent cipher (L.readFile src) $ L.writeFile dest
|
2011-04-16 21:41:14 -04:00
|
|
|
|
return True
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
2011-11-22 18:20:55 -04:00
|
|
|
|
storeHelper :: FilePath -> Key -> (FilePath -> IO Bool) -> IO Bool
|
2011-12-02 14:56:48 -04:00
|
|
|
|
storeHelper d key a = do
|
2011-12-15 18:11:42 -04:00
|
|
|
|
let dest = Prelude.head $ locations d key
|
2011-12-02 14:56:48 -04:00
|
|
|
|
let dir = parentDir dest
|
|
|
|
|
createDirectoryIfMissing True dir
|
|
|
|
|
allowWrite dir
|
|
|
|
|
ok <- a dest
|
|
|
|
|
when ok $ do
|
|
|
|
|
preventWrite dest
|
|
|
|
|
preventWrite dir
|
|
|
|
|
return ok
|
2011-04-16 21:41:14 -04:00
|
|
|
|
|
|
|
|
|
retrieve :: FilePath -> Key -> FilePath -> Annex Bool
|
2011-11-22 18:20:55 -04:00
|
|
|
|
retrieve d k f = liftIO $ withStoredFile d k $ \file -> copyFileExternal file f
|
2011-04-16 21:41:14 -04:00
|
|
|
|
|
|
|
|
|
retrieveEncrypted :: FilePath -> (Cipher, Key) -> FilePath -> Annex Bool
|
|
|
|
|
retrieveEncrypted d (cipher, enck) f =
|
2011-11-22 18:20:55 -04:00
|
|
|
|
liftIO $ withStoredFile d enck $ \file -> catchBoolIO $ do
|
|
|
|
|
withDecryptedContent cipher (L.readFile file) $ L.writeFile f
|
2011-04-17 00:57:29 -04:00
|
|
|
|
return True
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
2011-03-30 14:32:08 -04:00
|
|
|
|
remove :: FilePath -> Key -> Annex Bool
|
2011-11-22 18:20:55 -04:00
|
|
|
|
remove d k = liftIO $ withStoredFile d k $ \file -> catchBoolIO $ do
|
|
|
|
|
let dir = parentDir file
|
2011-04-17 00:57:29 -04:00
|
|
|
|
allowWrite dir
|
|
|
|
|
removeFile file
|
|
|
|
|
removeDirectory dir
|
|
|
|
|
return True
|
2011-03-30 13:18:46 -04:00
|
|
|
|
|
2011-11-09 18:33:15 -04:00
|
|
|
|
checkPresent :: FilePath -> Key -> Annex (Either String Bool)
|
2011-11-22 18:20:55 -04:00
|
|
|
|
checkPresent d k = liftIO $ catchMsgIO $ withStoredFile d k $
|
|
|
|
|
const $ return True -- withStoredFile checked that it exists
|