From a64106dcef5c5aad825662ef115cb2a1cc6985a8 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 10 Jun 2013 13:10:30 -0400 Subject: [PATCH] Supports indirect mode on encfs in paranoia mode, and other filesystems that do not support hard links, but do support symlinks and other POSIX filesystem features. --- Command/Add.hs | 43 +++++++++++++++++++++++++++---------------- Command/ReKey.hs | 15 ++++----------- Init.hs | 2 -- Remote/Rsync.hs | 17 ++++------------- Utility/CopyFile.hs | 25 ++++++++++++++++++++++--- debian/changelog | 8 ++++++++ 6 files changed, 65 insertions(+), 45 deletions(-) diff --git a/Command/Add.hs b/Command/Add.hs index fe1a6b13ac..6a2261d1f4 100644 --- a/Command/Add.hs +++ b/Command/Add.hs @@ -80,20 +80,21 @@ start file = ifAnnexed file addpresent add {- The file that's being added is locked down before a key is generated, - to prevent it from being modified in between. It's hard linked into a - - temporary location, and its writable bits are removed. It could still be - - written to by a process that already has it open for writing. + - temporary location (to prevent it being replaced with another file), + - and its writable bits are removed. It could still be written to by a + - process that already has it open for writing. + - + - On a crippled filesystem, no lock down is done; the file can be modified + - at any time, and the no hard link is made. + - + - On a filesystem without hard links, but not otherwise crippled, + - no hard link is made, but the write bit is still removed. - - Lockdown can fail if a file gets deleted, and Nothing will be returned. -} lockDown :: FilePath -> Annex (Maybe KeySource) lockDown file = ifM (crippledFileSystem) - ( liftIO $ catchMaybeIO $ do - cache <- genInodeCache file - return $ KeySource - { keyFilename = file - , contentLocation = file - , inodeCache = cache - } + ( liftIO $ catchMaybeIO nohardlink , do tmp <- fromRepo gitAnnexTmpDir createAnnexDirectory tmp @@ -102,14 +103,24 @@ lockDown file = ifM (crippledFileSystem) (tmpfile, h) <- openTempFile tmp (takeFileName file) hClose h nukeFile tmpfile - createLink file tmpfile - cache <- genInodeCache tmpfile - return $ KeySource - { keyFilename = file - , contentLocation = tmpfile - , inodeCache = cache - } + withhardlink tmpfile `catchIO` const nohardlink ) + where + nohardlink = do + cache <- genInodeCache file + return $ KeySource + { keyFilename = file + , contentLocation = file + , inodeCache = cache + } + withhardlink tmpfile = do + createLink file tmpfile + cache <- genInodeCache tmpfile + return $ KeySource + { keyFilename = file + , contentLocation = tmpfile + , inodeCache = cache + } {- Ingests a locked down file into the annex. - diff --git a/Command/ReKey.hs b/Command/ReKey.hs index 05fd73f1b9..d7b277fa69 100644 --- a/Command/ReKey.hs +++ b/Command/ReKey.hs @@ -7,8 +7,6 @@ module Command.ReKey where -import System.PosixCompat.Files - import Common.Annex import Command import qualified Annex @@ -17,7 +15,6 @@ import Annex.Content import qualified Command.Add import Logs.Web import Logs.Location -import Config import Utility.CopyFile def :: [Command] @@ -49,18 +46,14 @@ perform file oldkey newkey = do return True next $ cleanup file oldkey newkey -{- Make a hard link to the old key content, to avoid wasting disk space. -} +{- Make a hard link to the old key content (when supported), + - to avoid wasting disk space. -} linkKey :: Key -> Key -> Annex Bool linkKey oldkey newkey = getViaTmpUnchecked newkey $ \tmp -> do src <- calcRepo $ gitAnnexLocation oldkey - ifM (liftIO $ doesFileExist tmp) + liftIO $ ifM (doesFileExist tmp) ( return True - , ifM crippledFileSystem - ( liftIO $ copyFileExternal src tmp - , do - liftIO $ createLink src tmp - return True - ) + , createLinkOrCopy src tmp ) cleanup :: FilePath -> Key -> Key -> CommandCleanup diff --git a/Init.hs b/Init.hs index 6409fe9c4a..09e80eebde 100644 --- a/Init.hs +++ b/Init.hs @@ -140,8 +140,6 @@ probeCrippledFileSystem = do probe f = catchBoolIO $ do let f2 = f ++ "2" nukeFile f2 - createLink f f2 - nukeFile f2 createSymbolicLink f f2 nukeFile f2 preventWrite f diff --git a/Remote/Rsync.hs b/Remote/Rsync.hs index f7abbbf2a6..228a66d51b 100644 --- a/Remote/Rsync.hs +++ b/Remote/Rsync.hs @@ -264,7 +264,7 @@ rsyncRemote o callback params = do - - This would not be necessary if the hash directory structure used locally - was always the same as that used on the rsync remote. So if that's ever - - unified, this gets nicer. Especially in the crippled filesystem case. + - unified, this gets nicer. - (When we have the right hash directory structure, we can just - pass --include=X --include=X/Y --include=X/Y/file --exclude=*) -} @@ -272,20 +272,11 @@ rsyncSend :: RsyncOpts -> MeterUpdate -> Key -> Bool -> FilePath -> Annex Bool rsyncSend o callback k canrename src = withRsyncScratchDir $ \tmp -> do let dest = tmp Prelude.head (keyPaths k) liftIO $ createDirectoryIfMissing True $ parentDir dest - ok <- if canrename + ok <- liftIO $ if canrename then do - liftIO $ renameFile src dest + renameFile src dest return True - else ifM crippledFileSystem - ( liftIO $ copyFileExternal src dest - , do -#ifndef __WINDOWS__ - liftIO $ createLink src dest - return True -#else - liftIO $ copyFileExternal src dest -#endif - ) + else createLinkOrCopy src dest ps <- sendParams if ok then rsyncRemote o (Just callback) $ ps ++ diff --git a/Utility/CopyFile.hs b/Utility/CopyFile.hs index 18290669d9..bb0600aa9d 100644 --- a/Utility/CopyFile.hs +++ b/Utility/CopyFile.hs @@ -1,11 +1,16 @@ -{- git-annex file copying +{- file copying - - - Copyright 2010,2012 Joey Hess + - Copyright 2010-2013 Joey Hess - - Licensed under the GNU GPL version 3 or higher. -} -module Utility.CopyFile (copyFileExternal) where +{-# LANGUAGE CPP #-} + +module Utility.CopyFile ( + copyFileExternal, + createLinkOrCopy +) where import Common import qualified Build.SysConfig as SysConfig @@ -23,3 +28,17 @@ copyFileExternal src dest = do , (SysConfig.cp_a, Param "-a") , (SysConfig.cp_p && not SysConfig.cp_a, Param "-p") ] + +{- Create a hard link if the filesystem allows it, and fall back to copying + - the file. -} +createLinkOrCopy :: FilePath -> FilePath -> IO Bool +#ifndef __WINDOWS__ +createLinkOrCopy src dest = go `catchIO` const fallback + where + go = do + createLink src dest + return True + fallback = copyFileExternal src dest +#else +createLinkOrCopy = copyFileExternal +#endif diff --git a/debian/changelog b/debian/changelog index 3b696fe84b..f5a8f51287 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +git-annex (4.20130602) UNRELEASED; urgency=low + + * Supports indirect mode on encfs in paranoia mode, and other + filesystems that do not support hard links, but do support + symlinks and other POSIX filesystem features. + + -- Joey Hess Mon, 10 Jun 2013 12:52:44 -0400 + git-annex (4.20130601) unstable; urgency=medium * XMPP: Git push over xmpp made much more robust.