2011-03-30 18:56:31 +00:00
|
|
|
|
{- 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
|
|
|
|
|
|
2011-04-16 22:22:52 +00:00
|
|
|
|
import qualified Data.ByteString.Lazy.Char8 as L
|
2011-03-30 17:18:46 +00:00
|
|
|
|
import IO
|
|
|
|
|
import Control.Exception.Extensible (IOException)
|
|
|
|
|
import qualified Data.Map as M
|
|
|
|
|
import Control.Monad (when)
|
|
|
|
|
import Control.Monad.State (liftIO)
|
2011-03-30 18:56:31 +00:00
|
|
|
|
import System.Directory hiding (copyFile)
|
2011-03-30 17:18:46 +00:00
|
|
|
|
import System.FilePath
|
|
|
|
|
|
|
|
|
|
import RemoteClass
|
|
|
|
|
import Types
|
|
|
|
|
import qualified GitRepo as Git
|
|
|
|
|
import qualified Annex
|
|
|
|
|
import UUID
|
|
|
|
|
import Locations
|
|
|
|
|
import CopyFile
|
2011-03-30 18:32:08 +00:00
|
|
|
|
import Config
|
2011-03-30 18:56:31 +00:00
|
|
|
|
import Content
|
|
|
|
|
import Utility
|
2011-03-30 18:00:54 +00:00
|
|
|
|
import Remote.Special
|
2011-04-17 04:40:23 +00:00
|
|
|
|
import Remote.Encryptable
|
2011-04-16 22:22:52 +00:00
|
|
|
|
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)
|
2011-04-16 22:22:52 +00:00
|
|
|
|
gen r u c = do
|
2011-03-30 18:32:08 +00:00
|
|
|
|
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
|
|
|
|
|
}
|
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
|
|
|
|
|
let dir = case M.lookup "directory" c of
|
|
|
|
|
Nothing -> error "Specify directory="
|
|
|
|
|
Just d -> d
|
|
|
|
|
e <- liftIO $ doesDirectoryExist dir
|
|
|
|
|
when (not e) $ error $ "Directory does not exist: " ++ dir
|
2011-04-16 20:29:28 +00:00
|
|
|
|
c' <- encryptionSetup c
|
2011-03-30 17:18:46 +00:00
|
|
|
|
|
2011-03-30 18:32:08 +00:00
|
|
|
|
-- The directory is stored in git config, not in this remote's
|
|
|
|
|
-- persistant state, so it can vary between hosts.
|
2011-04-16 20:29:28 +00:00
|
|
|
|
gitConfigSpecialRemote u c' "directory" dir
|
|
|
|
|
return $ M.delete "directory" c'
|
2011-03-30 17:18:46 +00:00
|
|
|
|
|
2011-03-30 18:32:08 +00:00
|
|
|
|
dirKey :: FilePath -> Key -> FilePath
|
2011-04-02 17:49:03 +00:00
|
|
|
|
dirKey d k = d </> hashDirMixed k </> f </> f
|
2011-03-30 18:56:31 +00:00
|
|
|
|
where
|
|
|
|
|
f = keyFile k
|
2011-03-30 17:18:46 +00:00
|
|
|
|
|
2011-04-17 01:41:14 +00:00
|
|
|
|
store :: FilePath -> Key -> Annex Bool
|
|
|
|
|
store d k = do
|
2011-03-30 17:18:46 +00:00
|
|
|
|
g <- Annex.gitRepo
|
2011-04-17 01:41:14 +00:00
|
|
|
|
let src = gitAnnexLocation g k
|
|
|
|
|
let dest = dirKey d k
|
2011-04-17 04:57:29 +00:00
|
|
|
|
liftIO $ catchBool $ storeHelper dest $ copyFile src dest
|
2011-04-17 01:41:14 +00:00
|
|
|
|
|
|
|
|
|
storeEncrypted :: FilePath -> (Cipher, Key) -> Key -> Annex Bool
|
|
|
|
|
storeEncrypted d (cipher, enck) k = do
|
|
|
|
|
g <- Annex.gitRepo
|
|
|
|
|
let src = gitAnnexLocation g k
|
|
|
|
|
let dest = dirKey d enck
|
2011-04-17 04:57:29 +00:00
|
|
|
|
liftIO $ catchBool $ storeHelper dest $ encrypt src dest
|
2011-03-30 18:56:31 +00:00
|
|
|
|
where
|
2011-04-17 01:41:14 +00:00
|
|
|
|
encrypt src dest = do
|
|
|
|
|
content <- L.readFile src
|
|
|
|
|
withEncryptedContent cipher content $ L.writeFile dest
|
|
|
|
|
return True
|
2011-03-30 17:18:46 +00:00
|
|
|
|
|
2011-04-17 01:41:14 +00:00
|
|
|
|
storeHelper :: FilePath -> IO Bool -> IO Bool
|
|
|
|
|
storeHelper dest a = do
|
|
|
|
|
let dir = parentDir dest
|
|
|
|
|
createDirectoryIfMissing True dir
|
|
|
|
|
allowWrite dir
|
|
|
|
|
ok <- a
|
|
|
|
|
when ok $ do
|
|
|
|
|
preventWrite dest
|
|
|
|
|
preventWrite dir
|
|
|
|
|
return ok
|
|
|
|
|
|
|
|
|
|
retrieve :: FilePath -> Key -> FilePath -> Annex Bool
|
|
|
|
|
retrieve d k f = liftIO $ copyFile (dirKey d k) f
|
|
|
|
|
|
|
|
|
|
retrieveEncrypted :: FilePath -> (Cipher, Key) -> FilePath -> Annex Bool
|
|
|
|
|
retrieveEncrypted d (cipher, enck) f =
|
2011-04-17 04:57:29 +00:00
|
|
|
|
liftIO $ catchBool $ do
|
|
|
|
|
content <- L.readFile (dirKey d enck)
|
|
|
|
|
withDecryptedContent cipher content $ L.writeFile f
|
|
|
|
|
return True
|
2011-03-30 17:18:46 +00:00
|
|
|
|
|
2011-03-30 18:32:08 +00:00
|
|
|
|
remove :: FilePath -> Key -> Annex Bool
|
2011-04-17 04:57:29 +00:00
|
|
|
|
remove d k = liftIO $ catchBool $ do
|
|
|
|
|
allowWrite dir
|
|
|
|
|
removeFile file
|
|
|
|
|
removeDirectory dir
|
|
|
|
|
return True
|
2011-03-30 18:56:31 +00:00
|
|
|
|
where
|
|
|
|
|
file = dirKey d k
|
|
|
|
|
dir = parentDir file
|
2011-03-30 17:18:46 +00:00
|
|
|
|
|
2011-03-30 18:32:08 +00:00
|
|
|
|
checkPresent :: FilePath -> Key -> Annex (Either IOException Bool)
|
|
|
|
|
checkPresent d k = liftIO $ try $ doesFileExist (dirKey d k)
|