packages feed

git-annex 8.20201103 → 8.20201116

raw patch · 223 files changed

+2492/−1849 lines, 223 files

Files

Annex.hs view
@@ -5,7 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} -{-# LANGUAGE GeneralizedNewtypeDeriving, PackageImports, BangPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving, BangPatterns #-}  module Annex ( 	Annex,
Annex/AdjustedBranch.hs view
@@ -1,6 +1,6 @@ {- adjusted branch  -- - Copyright 2016-2018 Joey Hess <id@joeyh.name>+ - Copyright 2016-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -57,11 +57,13 @@ import Annex.GitOverlay import Utility.Tmp.Dir import Utility.CopyFile+import Utility.Directory.Create import qualified Database.Keys import Config  import qualified Data.Map as M import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P  -- How to perform various adjustments to a TreeItem. class AdjustTreeItem t where@@ -110,11 +112,10 @@ adjustToSymlink :: TreeItem -> Annex (Maybe TreeItem) adjustToSymlink = adjustToSymlink' gitAnnexLink -adjustToSymlink' :: (FilePath -> Key -> Git.Repo -> GitConfig -> IO FilePath) -> TreeItem -> Annex (Maybe TreeItem)+adjustToSymlink' :: (RawFilePath -> Key -> Git.Repo -> GitConfig -> IO RawFilePath) -> TreeItem -> Annex (Maybe TreeItem) adjustToSymlink' gitannexlink ti@(TreeItem f _m s) = catKey s >>= \case 	Just k -> do-		absf <- inRepo $ \r -> absPath $ -			fromRawFilePath $ fromTopFilePath f r+		absf <- inRepo $ \r -> absPath $ fromTopFilePath f r 		linktarget <- calcRepo $ gitannexlink absf k 		Just . TreeItem f (fromTreeItemType TreeSymlink) 			<$> hashSymlink linktarget@@ -295,7 +296,7 @@   where 	setup = do 		lck <- fromRepo $ indexFileLock . indexFile-		liftIO $ Git.LockFile.openLock lck+		liftIO $ Git.LockFile.openLock (fromRawFilePath lck) 	cleanup = liftIO . Git.LockFile.closeLock  {- Commits a given adjusted tree, with the provided parent ref.@@ -376,23 +377,27 @@ 	 - index file is currently locked.) 	 -} 	changestomerge (Just updatedorig) = withOtherTmp $ \othertmpdir -> do-		git_dir <- fromRawFilePath <$> fromRepo Git.localGitDir+		git_dir <- fromRepo Git.localGitDir+		let git_dir' = fromRawFilePath git_dir 		tmpwt <- fromRepo gitAnnexMergeDir-		withTmpDirIn othertmpdir "git" $ \tmpgit -> withWorkTreeRelated tmpgit $+		withTmpDirIn (fromRawFilePath othertmpdir) "git" $ \tmpgit -> withWorkTreeRelated tmpgit $ 			withemptydir git_dir tmpwt $ withWorkTree tmpwt $ do 				liftIO $ writeFile (tmpgit </> "HEAD") (fromRef updatedorig) 				-- Copy in refs and packed-refs, to work 				-- around bug in git 2.13.0, which 				-- causes it not to look in GIT_DIR for refs. 				refs <- liftIO $ dirContentsRecursive $-					git_dir </> "refs"-				let refs' = (git_dir </> "packed-refs") : refs+					git_dir' </> "refs"+				let refs' = (git_dir' </> "packed-refs") : refs 				liftIO $ forM_ refs' $ \src -> 					whenM (doesFileExist src) $ do-						dest <- relPathDirToFile git_dir src-						let dest' = tmpgit </> dest-						createDirectoryUnder git_dir (takeDirectory dest')-						void $ createLinkOrCopy src dest'+						dest <- relPathDirToFile git_dir+							(toRawFilePath src)+						let dest' = toRawFilePath tmpgit P.</> dest+						createDirectoryUnder git_dir+							(P.takeDirectory dest')+						void $ createLinkOrCopy src+							(fromRawFilePath dest') 				-- This reset makes git merge not care 				-- that the work tree is empty; otherwise 				-- it will think that all the files have@@ -418,7 +423,7 @@ 		setup = do 			whenM (doesDirectoryExist d) $ 				removeDirectoryRecursive d-			createDirectoryUnder git_dir d+			createDirectoryUnder git_dir (toRawFilePath d) 		cleanup _ = removeDirectoryRecursive d  	{- A merge commit has been made between the basisbranch and 
Annex/AutoMerge.hs view
@@ -176,7 +176,7 @@ 				-- files, so delete here. 				unless inoverlay $ 					unless (islocked LsFiles.valUs) $-						liftIO $ nukeFile file+						liftIO $ removeWhenExistsWith removeLink file 			| otherwise -> do 				-- Only resolve using symlink when both 				-- were locked, otherwise use unlocked@@ -230,7 +230,7 @@ 		| otherwise = pure f  	makesymlink key dest = do-		l <- calcRepo $ gitAnnexLink dest key+		l <- calcRepo $ gitAnnexLink (toRawFilePath dest) key 		unless inoverlay $ replacewithsymlink dest l 		dest' <- toRawFilePath <$> stagefile dest 		stageSymlink dest' =<< hashSymlink l@@ -241,7 +241,7 @@ 	makepointer key dest destmode = do 		unless inoverlay $  			unlessM (reuseOldFile unstagedmap key file dest) $-				linkFromAnnex key dest destmode >>= \case+				linkFromAnnex key (toRawFilePath dest) destmode >>= \case 					LinkAnnexFailed -> liftIO $ 						writePointerFile (toRawFilePath dest) key destmode 					_ -> noop@@ -267,7 +267,7 @@ 					Nothing -> noop 					Just sha -> do 						link <- catSymLinkTarget sha-						replacewithsymlink item (fromRawFilePath link)+						replacewithsymlink item link 			-- And when grafting in anything else vs a symlink, 			-- the work tree already contains what we want. 			(_, Just TreeSymlink) -> noop@@ -309,7 +309,7 @@ 		<$> mapM Database.Keys.getInodeCaches resolvedks 	forM_ (M.toList unstagedmap) $ \(i, f) -> 		whenM (matchesresolved is i f) $-			liftIO $ nukeFile f+			liftIO $ removeWhenExistsWith removeLink f   where 	fs = S.fromList resolvedfs 	ks = S.fromList resolvedks@@ -363,7 +363,7 @@ 		let f' = fromRawFilePath f 		if isSymbolicLink s 			then pure $ Just (Left f', f')-			else withTSDelta (\d -> liftIO $ toInodeCache d f' s)+			else withTSDelta (\d -> liftIO $ toInodeCache d f s) 				>>= return . \case 					Just i -> Just (Right (inodeCacheToKey Strongly i), f') 					Nothing -> Nothing
Annex/Branch.hs view
@@ -41,6 +41,7 @@ import Data.Char import Data.ByteString.Builder import Control.Concurrent (threadDelay)+import qualified System.FilePath.ByteString as P  import Annex.Common import Types.BranchState@@ -76,6 +77,7 @@ import qualified Annex import Annex.Hook import Utility.Directory.Stream+import qualified Utility.RawFilePath as R  {- Name of the branch that is used to store git-annex's information. -} name :: Git.Ref@@ -446,7 +448,7 @@ prepareModifyIndex :: JournalLocked -> Annex () prepareModifyIndex _jl = do 	index <- fromRepo gitAnnexIndex-	void $ liftIO $ tryIO $ removeFile $ index ++ ".lock"+	void $ liftIO $ tryIO $ R.removeLink (index <> ".lock")  {- Runs an action using the branch's index file. -} withIndex :: Annex a -> Annex a@@ -455,7 +457,7 @@ withIndex' bootstrapping a = withIndexFile AnnexIndexFile $ \f -> do 	checkIndexOnce $ unlessM (liftIO $ doesFileExist f) $ do 		unless bootstrapping create-		createAnnexDirectory $ takeDirectory f+		createAnnexDirectory $ toRawFilePath $ takeDirectory f 		unless bootstrapping $ inRepo genIndex 	a @@ -477,7 +479,7 @@ {- Checks if the index needs to be updated. -} needUpdateIndex :: Git.Ref -> Annex Bool needUpdateIndex branchref = do-	f <- fromRepo gitAnnexIndexStatus+	f <- fromRawFilePath <$> fromRepo gitAnnexIndexStatus 	committedref <- Git.Ref . firstLine' <$> 		liftIO (catchDefaultIO mempty $ B.readFile f) 	return (committedref /= branchref)@@ -506,19 +508,19 @@ 	prepareModifyIndex jl 	g <- gitRepo 	let dir = gitAnnexJournalDir g-	(jlogf, jlogh) <- openjlog tmpdir+	(jlogf, jlogh) <- openjlog (fromRawFilePath tmpdir) 	h <- hashObjectHandle 	withJournalHandle $ \jh -> 		Git.UpdateIndex.streamUpdateIndex g 			[genstream dir h jh jlogh] 	commitindex-	liftIO $ cleanup dir jlogh jlogf+	liftIO $ cleanup (fromRawFilePath dir) jlogh jlogf   where 	genstream dir h jh jlogh streamer = readDirectory jh >>= \case 		Nothing -> return () 		Just file -> do 			unless (dirCruft file) $ do-				let path = dir </> file+				let path = dir P.</> toRawFilePath file 				sha <- Git.HashObject.hashFile h path 				hPutStrLn jlogh file 				streamer $ Git.UpdateIndex.updateIndexLine@@ -533,7 +535,7 @@ 		stagedfs <- lines <$> hGetContents jlogh 		mapM_ (removeFile . (dir </>)) stagedfs 		hClose jlogh-		nukeFile jlogf+		removeWhenExistsWith removeLink jlogf 	openjlog tmpdir = liftIO $ openTempFile tmpdir "jlog"  {- This is run after the refs have been merged into the index,@@ -666,7 +668,7 @@ 	S.fromList . mapMaybe Git.Sha.extractSha . B8.lines <$> content   where 	content = do-		f <- fromRepo gitAnnexIgnoredRefs+		f <- fromRawFilePath <$> fromRepo gitAnnexIgnoredRefs 		liftIO $ catchDefaultIO mempty $ B.readFile f  addMergedRefs :: [(Git.Sha, Git.Branch)] -> Annex ()@@ -684,7 +686,7 @@  getMergedRefs' :: Annex [(Git.Sha, Git.Branch)] getMergedRefs' = do-	f <- fromRepo gitAnnexMergedRefs+	f <- fromRawFilePath <$> fromRepo gitAnnexMergedRefs 	s <- liftIO $ catchDefaultIO mempty $ B.readFile f 	return $ map parse $ B8.lines s   where
Annex/ChangedRefs.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Annex.ChangedRefs 	( ChangedRefs(..) 	, ChangedRefsHandle@@ -17,6 +19,7 @@ import Annex.Common import Utility.DirWatcher import Utility.DirWatcher.Types+import Utility.Directory.Create import qualified Git import Git.Sha import qualified Utility.SimpleProtocol as Proto@@ -25,6 +28,7 @@ import Control.Concurrent.STM import Control.Concurrent.STM.TBMChan import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P  newtype ChangedRefs = ChangedRefs [Git.Ref] 	deriving (Show)@@ -77,8 +81,8 @@ 	chan <- liftIO $ newTBMChanIO 100 	 	g <- gitRepo-	let gittop = fromRawFilePath (Git.localGitDir g)-	let refdir = gittop </> "refs"+	let gittop = Git.localGitDir g+	let refdir = gittop P.</> "refs" 	liftIO $ createDirectoryUnder gittop refdir  	let notifyhook = Just $ notifyHook chan@@ -89,7 +93,9 @@  	if canWatch 		then do-			h <- liftIO $ watchDir refdir (const False) True hooks id+			h <- liftIO $ watchDir+				(fromRawFilePath refdir)+				(const False) True hooks id 			return $ Just $ ChangedRefsHandle h chan 		else return Nothing 
Annex/CheckAttr.hs view
@@ -26,7 +26,7 @@ 	, "annex.largefiles" 	] -checkAttr :: Git.Attr -> FilePath -> Annex String+checkAttr :: Git.Attr -> RawFilePath -> Annex String checkAttr attr file = withCheckAttrHandle $ \h ->  	liftIO $ Git.checkAttr h attr file 
Annex/CheckIgnore.hs view
@@ -22,7 +22,7 @@  newtype CheckGitIgnore = CheckGitIgnore Bool -checkIgnored :: CheckGitIgnore -> FilePath -> Annex Bool+checkIgnored :: CheckGitIgnore -> RawFilePath -> Annex Bool checkIgnored (CheckGitIgnore False) _ = pure False checkIgnored (CheckGitIgnore True) file = 	ifM (Annex.getState Annex.force)
Annex/Content.hs view
@@ -1,6 +1,6 @@ {- git-annex file content managing  -- - Copyright 2010-2019 Joey Hess <id@joeyh.name>+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -131,8 +131,7 @@ {- A safer check; the key's content must not only be present, but  - is not in the process of being removed. -} inAnnexSafe :: Key -> Annex (Maybe Bool)-inAnnexSafe key = -	inAnnex' (fromMaybe True) (Just False) (go . fromRawFilePath) key+inAnnexSafe key = inAnnex' (fromMaybe True) (Just False) go key   where 	is_locked = Nothing 	is_unlocked = Just True@@ -145,7 +144,7 @@ 	{- The content file must exist, but the lock file generally 	 - won't exist unless a removal is in process. -} 	checklock (Just lockfile) contentfile =-		ifM (liftIO $ doesFileExist contentfile)+		ifM (liftIO $ doesFileExist (fromRawFilePath contentfile)) 			( checkOr is_unlocked lockfile 			, return is_missing 			)@@ -154,7 +153,7 @@ 		Just True -> is_locked 		Just False -> is_unlocked #else-	checklock Nothing contentfile = liftIO $ ifM (doesFileExist contentfile)+	checklock Nothing contentfile = liftIO $ ifM (doesFileExist (fromRawFilePath contentfile)) 		( lockShared contentfile >>= \case 			Nothing -> return is_locked 			Just lockhandle -> do@@ -165,13 +164,13 @@ 	{- In Windows, see if we can take a shared lock. If so,  	 - remove the lock file to clean up after ourselves. -} 	checklock (Just lockfile) contentfile =-		ifM (liftIO $ doesFileExist contentfile)+		ifM (liftIO $ doesFileExist (fromRawFilePath contentfile)) 			( modifyContent lockfile $ liftIO $ 				lockShared lockfile >>= \case 					Nothing -> return is_locked 					Just lockhandle -> do 						dropLock lockhandle-						void $ tryIO $ nukeFile lockfile+						void $ tryIO $ removeWhenExistsWith removeLink lockfile 						return is_unlocked 			, return is_missing 			)@@ -180,7 +179,7 @@ {- Windows has to use a separate lock file from the content, since  - locking the actual content file would interfere with the user's  - use of it. -}-contentLockFile :: Key -> Annex (Maybe FilePath)+contentLockFile :: Key -> Annex (Maybe RawFilePath) #ifndef mingw32_HOST_OS contentLockFile _ = pure Nothing #else@@ -236,7 +235,7 @@  {- Passed the object content file, and maybe a separate lock file to use,  - when the content file itself should not be locked. -}-type ContentLocker = FilePath -> Maybe LockFile -> Annex (Maybe LockHandle)+type ContentLocker = RawFilePath -> Maybe LockFile -> Annex (Maybe LockHandle)  #ifndef mingw32_HOST_OS posixLocker :: (Maybe FileMode -> LockFile -> Annex (Maybe LockHandle)) -> LockFile -> Annex (Maybe LockHandle)@@ -262,7 +261,7 @@  - the file that is locked eg on Windows a different file is locked. -} lockContentUsing :: ContentLocker -> Key -> Annex a -> Annex a -> Annex a lockContentUsing locker key fallback a = do-	contentfile <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)+	contentfile <- calcRepo (gitAnnexLocation key) 	lockfile <- contentLockFile key 	bracket 		(lock contentfile lockfile)@@ -295,22 +294,22 @@  	cleanuplockfile lockfile = modifyContent lockfile $ 		void $ liftIO $ tryIO $-			nukeFile lockfile+			removeWhenExistsWith R.removeLink lockfile  {- Runs an action, passing it the temp file to get,  - and if the action succeeds, verifies the file matches  - the key and moves the file into the annex as a key's content. -}-getViaTmp :: RetrievalSecurityPolicy -> VerifyConfig -> Key -> (FilePath -> Annex (Bool, Verification)) -> Annex Bool+getViaTmp :: RetrievalSecurityPolicy -> VerifyConfig -> Key -> (RawFilePath -> Annex (Bool, Verification)) -> Annex Bool getViaTmp rsp v key action = checkDiskSpaceToGet key False $ 	getViaTmpFromDisk rsp v key action  {- Like getViaTmp, but does not check that there is enough disk space  - for the incoming key. For use when the key content is already on disk  - and not being copied into place. -}-getViaTmpFromDisk :: RetrievalSecurityPolicy -> VerifyConfig -> Key -> (FilePath -> Annex (Bool, Verification)) -> Annex Bool+getViaTmpFromDisk :: RetrievalSecurityPolicy -> VerifyConfig -> Key -> (RawFilePath -> Annex (Bool, Verification)) -> Annex Bool getViaTmpFromDisk rsp v key action = checkallowed $ do 	tmpfile <- prepTmp key-	resuming <- liftIO $ doesFileExist tmpfile+	resuming <- liftIO $ R.doesPathExist tmpfile 	(ok, verification) <- action tmpfile 	-- When the temp file already had content, we don't know if 	-- that content is good or not, so only trust if it the action@@ -338,7 +337,8 @@ 				-- including perhaps the content of another 				-- file than the one that was requested, 				-- and so it's best not to keep it on disk.-				pruneTmpWorkDirBefore tmpfile (liftIO . nukeFile)+				pruneTmpWorkDirBefore tmpfile+					(liftIO . removeWhenExistsWith R.removeLink) 				return False 			) 		-- On transfer failure, the tmp file is left behind, in case@@ -371,7 +371,7 @@  - If the RetrievalSecurityPolicy requires verification and the key's  - backend doesn't support it, the verification will fail.  -}-verifyKeyContent :: RetrievalSecurityPolicy -> VerifyConfig -> Verification -> Key -> FilePath -> Annex Bool+verifyKeyContent :: RetrievalSecurityPolicy -> VerifyConfig -> Verification -> Key -> RawFilePath -> Annex Bool verifyKeyContent rsp v verification k f = case (rsp, verification) of 	(_, Verified) -> return True 	(RetrievalVerifiableKeysSecure, _) -> ifM (Backend.isVerifiable k)@@ -432,9 +432,8 @@  -} checkDiskSpaceToGet :: Key -> a -> Annex a -> Annex a checkDiskSpaceToGet key unabletoget getkey = do-	tmp <- fromRepo $ gitAnnexTmpObjectLocation key--	e <- liftIO $ doesFileExist tmp+	tmp <- fromRepo (gitAnnexTmpObjectLocation key)+	e <- liftIO $ doesFileExist (fromRawFilePath tmp) 	alreadythere <- liftIO $ if e 		then getFileSize tmp 		else return 0@@ -446,7 +445,7 @@ 		, return unabletoget 		) -prepTmp :: Key -> Annex FilePath+prepTmp :: Key -> Annex RawFilePath prepTmp key = do 	tmp <- fromRepo $ gitAnnexTmpObjectLocation key 	createAnnexDirectory (parentDir tmp)@@ -456,11 +455,11 @@  - the temp file. If the action throws an exception, the temp file is  - left behind, which allows for resuming.  -}-withTmp :: Key -> (FilePath -> Annex a) -> Annex a+withTmp :: Key -> (RawFilePath -> Annex a) -> Annex a withTmp key action = do 	tmp <- prepTmp key 	res <- action tmp-	pruneTmpWorkDirBefore tmp (liftIO . nukeFile)+	pruneTmpWorkDirBefore tmp (liftIO . removeWhenExistsWith R.removeLink) 	return res  {- Moves a key's content into .git/annex/objects/@@ -491,7 +490,7 @@  - accepted into the repository. Will display a warning message in this  - case. May also throw exceptions in some cases.  -}-moveAnnex :: Key -> FilePath -> Annex Bool+moveAnnex :: Key -> RawFilePath -> Annex Bool moveAnnex key src = ifM (checkSecureHashes' key) 	( do 		withObjectLoc key storeobject@@ -501,9 +500,11 @@   where 	storeobject dest = ifM (liftIO $ R.doesPathExist dest) 		( alreadyhave-		, modifyContent dest' $ do+		, modifyContent dest $ do 			freezeContent src-			liftIO $ moveFile src dest'+			liftIO $ moveFile+				(fromRawFilePath src)+				(fromRawFilePath dest) 			g <- Annex.gitRepo  			fs <- map (`fromTopFilePath` g) 				<$> Database.Keys.getAssociatedFiles key@@ -511,9 +512,7 @@ 				ics <- mapM (populatePointerFile (Restage True) key dest) fs 				Database.Keys.storeInodeCaches' key [dest] (catMaybes ics) 		)-	  where-		dest' = fromRawFilePath dest-	alreadyhave = liftIO $ removeFile src+	alreadyhave = liftIO $ R.removeLink src  checkSecureHashes :: Key -> Annex (Maybe String) checkSecureHashes key = ifM (Backend.isCryptographicallySecure key)@@ -535,20 +534,20 @@  {- Populates the annex object file by hard linking or copying a source  - file to it. -}-linkToAnnex :: Key -> FilePath -> Maybe InodeCache -> Annex LinkAnnexResult+linkToAnnex :: Key -> RawFilePath -> Maybe InodeCache -> Annex LinkAnnexResult linkToAnnex key src srcic = ifM (checkSecureHashes' key) 	( do-		dest <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)+		dest <- calcRepo (gitAnnexLocation key) 		modifyContent dest $ linkAnnex To key src srcic dest Nothing 	, return LinkAnnexFailed 	)  {- Makes a destination file be a link or copy from the annex object. -}-linkFromAnnex :: Key -> FilePath -> Maybe FileMode -> Annex LinkAnnexResult+linkFromAnnex :: Key -> RawFilePath -> Maybe FileMode -> Annex LinkAnnexResult linkFromAnnex key dest destmode = do 	src <- calcRepo (gitAnnexLocation key) 	srcic <- withTSDelta (liftIO . genInodeCache src)-	linkAnnex From key (fromRawFilePath src) srcic dest destmode+	linkAnnex From key src srcic dest destmode  data FromTo = From | To @@ -564,10 +563,10 @@  -  - Nothing is done if the destination file already exists.  -}-linkAnnex :: FromTo -> Key -> FilePath -> Maybe InodeCache -> FilePath -> Maybe FileMode -> Annex LinkAnnexResult+linkAnnex :: FromTo -> Key -> RawFilePath -> Maybe InodeCache -> RawFilePath -> Maybe FileMode -> Annex LinkAnnexResult linkAnnex _ _ _ Nothing _ _ = return LinkAnnexFailed linkAnnex fromto key src (Just srcic) dest destmode =-	withTSDelta (liftIO . genInodeCache dest') >>= \case+	withTSDelta (liftIO . genInodeCache dest) >>= \case 		Just destic -> do 			cs <- Database.Keys.getInodeCaches key 			if null cs@@ -584,27 +583,26 @@ 						Linked -> noop 				checksrcunchanged   where-	dest' = toRawFilePath dest 	failed = do 		Database.Keys.addInodeCaches key [srcic] 		return LinkAnnexFailed-	checksrcunchanged = withTSDelta (liftIO . genInodeCache (toRawFilePath src)) >>= \case+	checksrcunchanged = withTSDelta (liftIO . genInodeCache src) >>= \case 		Just srcic' | compareStrong srcic srcic' -> do-			destic <- withTSDelta (liftIO . genInodeCache dest')+			destic <- withTSDelta (liftIO . genInodeCache dest) 			Database.Keys.addInodeCaches key $ 				catMaybes [destic, Just srcic] 			return LinkAnnexOk 		_ -> do-			liftIO $ nukeFile dest+			liftIO $ removeWhenExistsWith R.removeLink dest 			failed  {- Removes the annex object file for a key. Lowlevel. -} unlinkAnnex :: Key -> Annex () unlinkAnnex key = do-	obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)+	obj <- calcRepo (gitAnnexLocation key) 	modifyContent obj $ do 		secureErase obj-		liftIO $ nukeFile obj+		liftIO $ removeWhenExistsWith R.removeLink obj  {- Runs an action to transfer an object's content.  -@@ -656,7 +654,7 @@  cleanObjectLoc :: Key -> Annex () -> Annex () cleanObjectLoc key cleaner = do-	file <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)+	file <- calcRepo (gitAnnexLocation key) 	void $ tryIO $ thawContentDir file 	cleaner 	liftIO $ removeparents file (3 :: Int)@@ -665,16 +663,15 @@ 	removeparents file n = do 		let dir = parentDir file 		maybe noop (const $ removeparents dir (n-1))-			<=< catchMaybeIO $ removeDirectory dir+			<=< catchMaybeIO $ removeDirectory (fromRawFilePath dir)  {- Removes a key's file from .git/annex/objects/  -} removeAnnex :: ContentRemovalLock -> Annex () removeAnnex (ContentRemovalLock key) = withObjectLoc key $ \file -> 	cleanObjectLoc key $ do-		let file' = fromRawFilePath file-		secureErase file'-		liftIO $ nukeFile file'+		secureErase file+		liftIO $ removeWhenExistsWith R.removeLink file 		g <- Annex.gitRepo  		mapM_ (\f -> void $ tryIO $ resetpointer $ fromTopFilePath f g) 			=<< Database.Keys.getAssociatedFiles key@@ -688,7 +685,7 @@ 		-- If it was a hard link to the annex object, 		-- that object might have been frozen as part of the 		-- removal process, so thaw it.-		, void $ tryIO $ thawContent $ fromRawFilePath file+		, void $ tryIO $ thawContent file 		)  {- Check if a file contains the unmodified content of the key.@@ -701,7 +698,7 @@   where 	go Nothing = return False 	go (Just fc) = isUnmodifiedCheap' key fc <||> expensivecheck fc-	expensivecheck fc = ifM (verifyKeyContent RetrievalAllKeysSecure AlwaysVerify UnVerified key (fromRawFilePath f))+	expensivecheck fc = ifM (verifyKeyContent RetrievalAllKeysSecure AlwaysVerify UnVerified key f) 		( do 			-- The file could have been modified while it was 			-- being verified. Detect that.@@ -736,14 +733,15 @@  - returns the file it was moved to. -} moveBad :: Key -> Annex FilePath moveBad key = do-	src <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)+	src <- calcRepo (gitAnnexLocation key) 	bad <- fromRepo gitAnnexBadDir-	let dest = bad </> takeFileName src+	let dest = bad P.</> P.takeFileName src+	let dest' = fromRawFilePath dest 	createAnnexDirectory (parentDir dest) 	cleanObjectLoc key $-		liftIO $ moveFile src dest+		liftIO $ moveFile (fromRawFilePath src) dest' 	logStatus key InfoMissing-	return dest+	return dest'  data KeyLocation = InAnnex | InAnywhere @@ -760,7 +758,7 @@ 	 -} 	s <- Annex.getState id 	depth <- gitAnnexLocationDepth <$> Annex.getGitConfig-	liftIO $ walk s depth dir+	liftIO $ walk s depth (fromRawFilePath dir)   where 	walk s depth dir = do 		contents <- catchDefaultIO [] (dirContents dir)@@ -825,7 +823,7 @@ 	go False = return False 	go True = do 		ok <- copy-		when ok $ thawContent file+		when ok $ thawContent (toRawFilePath file) 		return ok 	copy = ifM (liftIO $ doesFileExist file) 		( return True@@ -839,9 +837,9 @@  {- Finds files directly inside a directory like gitAnnexBadDir   - (not in subdirectories) and returns the corresponding keys. -}-dirKeys :: (Git.Repo -> FilePath) -> Annex [Key]+dirKeys :: (Git.Repo -> RawFilePath) -> Annex [Key] dirKeys dirspec = do-	dir <- fromRepo dirspec+	dir <- fromRawFilePath <$> fromRepo dirspec 	ifM (liftIO $ doesDirectoryExist dir) 		( do 			contents <- liftIO $ getDirectoryContents dir@@ -857,7 +855,7 @@  - Also, stale keys that can be proven to have no value  - (ie, their content is already present) are deleted.  -}-staleKeysPrune :: (Git.Repo -> FilePath) -> Bool -> Annex [Key]+staleKeysPrune :: (Git.Repo -> RawFilePath) -> Bool -> Annex [Key] staleKeysPrune dirspec nottransferred = do 	contents <- dirKeys dirspec 	@@ -866,8 +864,8 @@  	dir <- fromRepo dirspec 	forM_ dups $ \k ->-		pruneTmpWorkDirBefore (dir </> fromRawFilePath (keyFile k))-			(liftIO . removeFile)+		pruneTmpWorkDirBefore (dir P.</> keyFile k)+			(liftIO . R.removeLink)  	if nottransferred 		then do@@ -882,9 +880,9 @@  - This preserves the invariant that the workdir never exists without  - the content file.  -}-pruneTmpWorkDirBefore :: FilePath -> (FilePath -> Annex a) -> Annex a+pruneTmpWorkDirBefore :: RawFilePath -> (RawFilePath -> Annex a) -> Annex a pruneTmpWorkDirBefore f action = do-	let workdir = gitAnnexTmpWorkDir f+	let workdir = fromRawFilePath $ gitAnnexTmpWorkDir f 	liftIO $ whenM (doesDirectoryExist workdir) $ 		removeDirectoryRecursive workdir 	action f@@ -899,21 +897,22 @@  - the temporary work directory is retained (unless  - empty), so anything in it can be used on resume.  -}-withTmpWorkDir :: Key -> (FilePath -> Annex (Maybe a)) -> Annex (Maybe a)+withTmpWorkDir :: Key -> (RawFilePath -> Annex (Maybe a)) -> Annex (Maybe a) withTmpWorkDir key action = do 	-- Create the object file if it does not exist. This way, 	-- staleKeysPrune only has to look for object files, and can 	-- clean up gitAnnexTmpWorkDir for those it finds. 	obj <- prepTmp key-	unlessM (liftIO $ doesFileExist obj) $ do-		liftIO $ writeFile obj ""+	let obj' = fromRawFilePath obj+	unlessM (liftIO $ doesFileExist obj') $ do+		liftIO $ writeFile obj' "" 		setAnnexFilePerm obj 	let tmpdir = gitAnnexTmpWorkDir obj 	createAnnexDirectory tmpdir 	res <- action tmpdir 	case res of-		Just _ -> liftIO $ removeDirectoryRecursive tmpdir-		Nothing -> liftIO $ void $ tryIO $ removeDirectory tmpdir+		Just _ -> liftIO $ removeDirectoryRecursive (fromRawFilePath tmpdir)+		Nothing -> liftIO $ void $ tryIO $ removeDirectory (fromRawFilePath tmpdir) 	return res  {- Finds items in the first, smaller list, that are not
Annex/Content/LowLevel.hs view
@@ -9,8 +9,6 @@  module Annex.Content.LowLevel where -import System.PosixCompat.Files- import Annex.Common import Logs.Transfer import qualified Annex@@ -18,16 +16,20 @@ import Utility.FileMode import Utility.DataUnits import Utility.CopyFile+import qualified Utility.RawFilePath as R +import System.PosixCompat.Files+import qualified System.FilePath.ByteString as P+ {- Runs the secure erase command if set, otherwise does nothing.  - File may or may not be deleted at the end; caller is responsible for  - making sure it's deleted. -}-secureErase :: FilePath -> Annex ()+secureErase :: RawFilePath -> Annex () secureErase file = maybe noop go =<< annexSecureEraseCommand <$> Annex.getGitConfig   where 	go basecmd = void $ liftIO $ 		boolSystem "sh" [Param "-c", Param $ gencmd basecmd]-	gencmd = massReplace [ ("%file", shellEscape file) ]+	gencmd = massReplace [ ("%file", shellEscape (fromRawFilePath file)) ]  data LinkedOrCopied = Linked | Copied @@ -44,10 +46,10 @@  - execute bit will be set. The mode is not fully copied over because  - git doesn't support file modes beyond execute.  -}-linkOrCopy :: Key -> FilePath -> FilePath -> Maybe FileMode -> Annex (Maybe LinkedOrCopied)+linkOrCopy :: Key -> RawFilePath -> RawFilePath -> Maybe FileMode -> Annex (Maybe LinkedOrCopied) linkOrCopy = linkOrCopy' (annexThin <$> Annex.getGitConfig) -linkOrCopy' :: Annex Bool -> Key -> FilePath -> FilePath -> Maybe FileMode -> Annex (Maybe LinkedOrCopied)+linkOrCopy' :: Annex Bool -> Key -> RawFilePath -> RawFilePath -> Maybe FileMode -> Annex (Maybe LinkedOrCopied) linkOrCopy' canhardlink key src dest destmode = catchDefaultIO Nothing $ 	ifM canhardlink 		( hardlink@@ -58,30 +60,30 @@ 		s <- getstat 		if linkCount s > 1 			then copy s-			else liftIO (createLink src dest >> preserveGitMode dest destmode >> return (Just Linked))+			else liftIO (R.createLink src dest >> preserveGitMode dest destmode >> return (Just Linked)) 				`catchIO` const (copy s) 	copy s = ifM (checkedCopyFile' key src dest destmode s) 		( return (Just Copied) 		, return Nothing 		)-	getstat = liftIO $ getFileStatus src+	getstat = liftIO $ R.getFileStatus src  {- Checks disk space before copying. -}-checkedCopyFile :: Key -> FilePath -> FilePath -> Maybe FileMode -> Annex Bool+checkedCopyFile :: Key -> RawFilePath -> RawFilePath -> Maybe FileMode -> Annex Bool checkedCopyFile key src dest destmode = catchBoolIO $ 	checkedCopyFile' key src dest destmode-		=<< liftIO (getFileStatus src)+		=<< liftIO (R.getFileStatus src) -checkedCopyFile' :: Key -> FilePath -> FilePath -> Maybe FileMode -> FileStatus -> Annex Bool+checkedCopyFile' :: Key -> RawFilePath -> RawFilePath -> Maybe FileMode -> FileStatus -> Annex Bool checkedCopyFile' key src dest destmode s = catchBoolIO $-	ifM (checkDiskSpace' (fromIntegral $ fileSize s) (Just $ takeDirectory dest) key 0 True)+	ifM (checkDiskSpace' (fromIntegral $ fileSize s) (Just $ P.takeDirectory dest) key 0 True) 		( liftIO $-			copyFileExternal CopyAllMetaData src dest+			copyFileExternal CopyAllMetaData (fromRawFilePath src) (fromRawFilePath dest) 				<&&> preserveGitMode dest destmode 		, return False 		) -preserveGitMode :: FilePath -> Maybe FileMode -> IO Bool+preserveGitMode :: RawFilePath -> Maybe FileMode -> IO Bool preserveGitMode f (Just mode) 	| isExecutable mode = catchBoolIO $ do 		modifyFileMode f $ addModes executeModes@@ -99,12 +101,12 @@  - to be downloaded from the free space. This way, we avoid overcommitting  - when doing concurrent downloads.  -}-checkDiskSpace :: Maybe FilePath -> Key -> Integer -> Bool -> Annex Bool+checkDiskSpace :: Maybe RawFilePath -> Key -> Integer -> Bool -> Annex Bool checkDiskSpace destdir key = checkDiskSpace' (fromMaybe 1 (fromKey keySize key)) destdir key  {- Allows specifying the size of the key, if it's known, which is useful  - as not all keys know their size. -}-checkDiskSpace' :: Integer -> Maybe FilePath -> Key -> Integer -> Bool -> Annex Bool+checkDiskSpace' :: Integer -> Maybe RawFilePath -> Key -> Integer -> Bool -> Annex Bool checkDiskSpace' need destdir key alreadythere samefilesystem = ifM (Annex.getState Annex.force) 	( return True 	, do@@ -117,7 +119,7 @@ 		inprogress <- if samefilesystem 			then sizeOfDownloadsInProgress (/= key) 			else pure 0-		dir >>= liftIO . getDiskFree >>= \case+		dir >>= liftIO . getDiskFree . fromRawFilePath >>= \case 			Just have -> do 				reserve <- annexDiskReserve <$> Annex.getGitConfig 				let delta = need + reserve - have - alreadythere + inprogress@@ -128,7 +130,7 @@ 			_ -> return True 	)   where-	dir = maybe (fromRawFilePath <$> fromRepo gitAnnexDir) return destdir+	dir = maybe (fromRepo gitAnnexDir) return destdir  needMoreDiskSpace :: Integer -> String needMoreDiskSpace n = "not enough free space, need " ++ 
Annex/Content/PointerFile.hs view
@@ -25,6 +25,7 @@ #if ! defined(mingw32_HOST_OS) import Utility.Touch #endif+import qualified Utility.RawFilePath as R  {- Populates a pointer file with the content of a key.   -@@ -37,12 +38,12 @@   where 	go (Just k') | k == k' = do 		let f' = fromRawFilePath f-		destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f'-		liftIO $ nukeFile f'+		destmode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus f+		liftIO $ removeWhenExistsWith R.removeLink f 		(ic, populated) <- replaceWorkTreeFile f' $ \tmp -> do 			let tmp' = toRawFilePath tmp-			ok <- linkOrCopy k (fromRawFilePath obj) tmp destmode >>= \case-				Just _ -> thawContent tmp >> return True+			ok <- linkOrCopy k obj tmp' destmode >>= \case+				Just _ -> thawContent tmp' >> return True 				Nothing -> liftIO (writePointerFile tmp' k destmode) >> return False 			ic <- withTSDelta (liftIO . genInodeCache tmp') 			return (ic, ok)@@ -60,15 +61,16 @@ 	let file' = fromRawFilePath file 	st <- liftIO $ catchMaybeIO $ getFileStatus file' 	let mode = fmap fileMode st-	secureErase file'-	liftIO $ nukeFile file'+	secureErase file+	liftIO $ removeWhenExistsWith R.removeLink file 	ic <- replaceWorkTreeFile file' $ \tmp -> do-		liftIO $ writePointerFile (toRawFilePath tmp) key mode+		let tmp' = toRawFilePath tmp+		liftIO $ writePointerFile tmp' key mode #if ! defined(mingw32_HOST_OS) 		-- Don't advance mtime; this avoids unncessary re-smudging 		-- by git in some cases. 		liftIO $ maybe noop-			(\t -> touch tmp t False)+			(\t -> touch tmp' t False) 			(fmap modificationTimeHiRes st) #endif 		withTSDelta (liftIO . genInodeCache (toRawFilePath tmp))
Annex/Drop.hs view
@@ -64,7 +64,7 @@ 		(untrusted, have) <- trustPartition UnTrusted locs 		numcopies <- if null fs 			then getNumCopies-			else maximum <$> mapM (getFileNumCopies . fromRawFilePath) fs+			else maximum <$> mapM getFileNumCopies fs 		return (NumCopies (length have), numcopies, S.fromList untrusted)  	{- Check that we have enough copies still to drop the content.
Annex/FileMatcher.hs view
@@ -52,18 +52,19 @@ import Data.Either import qualified Data.Set as S -type GetFileMatcher = FilePath -> Annex (FileMatcher Annex)+type GetFileMatcher = RawFilePath -> Annex (FileMatcher Annex) -checkFileMatcher :: GetFileMatcher -> FilePath -> Annex Bool-checkFileMatcher getmatcher file = checkFileMatcher' getmatcher file (return True)+checkFileMatcher :: GetFileMatcher -> RawFilePath -> Annex Bool+checkFileMatcher getmatcher file =+	checkFileMatcher' getmatcher file (return True)  -- | Allows running an action when no matcher is configured for the file.-checkFileMatcher' :: GetFileMatcher -> FilePath -> Annex Bool -> Annex Bool+checkFileMatcher' :: GetFileMatcher -> RawFilePath -> Annex Bool -> Annex Bool checkFileMatcher' getmatcher file notconfigured = do 	matcher <- getmatcher file 	checkMatcher matcher Nothing afile S.empty notconfigured d   where-	afile = AssociatedFile (Just (toRawFilePath file))+	afile = AssociatedFile (Just file) 	-- checkMatcher will never use this, because afile is provided. 	d = return True @@ -71,7 +72,7 @@ checkMatcher matcher mkey afile notpresent notconfigured d 	| isEmpty matcher = notconfigured 	| otherwise = case (mkey, afile) of-		(_, AssociatedFile (Just file)) -> go =<< fileMatchInfo file+		(Nothing, AssociatedFile (Just file)) -> go =<< fileMatchInfo file 		(Just key, _) -> go (MatchingKey key afile) 		_ -> d   where
Annex/Fixup.hs view
@@ -13,23 +13,23 @@ import Git.Config import Types.GitConfig import Utility.Path+import Utility.Path.AbsRel import Utility.SafeCommand import Utility.Directory import Utility.Exception import Utility.Monad import Utility.FileSystemEncoding+import qualified Utility.RawFilePath as R import Utility.PartialPrelude  import System.IO-import System.FilePath-import System.PosixCompat.Files import Data.List import Data.Maybe import Control.Monad import Control.Monad.IfElse import qualified Data.Map as M-import qualified System.FilePath.ByteString as P import qualified Data.ByteString as S+import System.FilePath.ByteString import Control.Applicative import Prelude @@ -53,7 +53,7 @@ fixupDirect :: Repo -> Repo fixupDirect r@(Repo { location = l@(Local { gitdir = d, worktree = Nothing }) }) = do 	r-		{ location = l { worktree = Just (toRawFilePath (parentDir (fromRawFilePath d))) }+		{ location = l { worktree = Just (parentDir d) } 		, gitGlobalOpts = gitGlobalOpts r ++ 			[ Param "-c" 			, Param $ fromConfigKey coreBare ++ "=" ++ boolConfig False@@ -108,13 +108,12 @@ 		, return r 		)   where-	dotgit = w P.</> ".git"-	dotgit' = fromRawFilePath dotgit+	dotgit = w </> ".git" -	replacedotgit = whenM (doesFileExist dotgit') $ do-		linktarget <- relPathDirToFile (fromRawFilePath w) (fromRawFilePath d)-		nukeFile dotgit'-		createSymbolicLink linktarget dotgit'+	replacedotgit = whenM (doesFileExist (fromRawFilePath dotgit)) $ do+		linktarget <- relPathDirToFile w d+		removeWhenExistsWith R.removeLink dotgit+		R.createSymbolicLink linktarget dotgit 	 	unsetcoreworktree = 		maybe (error "unset core.worktree failed") (\_ -> return ())@@ -124,13 +123,14 @@ 		-- git-worktree sets up a "commondir" file that contains 		-- the path to the main git directory. 		-- Using --separate-git-dir does not.-		catchDefaultIO Nothing (headMaybe . lines <$> readFile (fromRawFilePath (d P.</> "commondir"))) >>= \case+		catchDefaultIO Nothing (headMaybe . lines <$> readFile (fromRawFilePath (d </> "commondir"))) >>= \case 			Just gd -> do 				-- Make the worktree's git directory 				-- contain an annex symlink to the main 				-- repository's annex directory.-				let linktarget = gd </> "annex"-				createSymbolicLink linktarget (dotgit' </> "annex")+				let linktarget = toRawFilePath gd </> "annex"+				R.createSymbolicLink linktarget+					(dotgit </> "annex") 			Nothing -> return ()  	-- Repo adjusted, so that symlinks to objects that get checked@@ -143,7 +143,7 @@  needsSubmoduleFixup :: Repo -> Bool needsSubmoduleFixup (Repo { location = (Local { worktree = Just _, gitdir = d }) }) =-	(".git" P.</> "modules") `S.isInfixOf` d+	(".git" </> "modules") `S.isInfixOf` d needsSubmoduleFixup _ = False  needsGitLinkFixup :: Repo -> IO Bool@@ -151,6 +151,6 @@ 	-- Optimization: Avoid statting .git in the common case; only 	-- when the gitdir is not in the usual place inside the worktree 	-- might .git be a file.-	| wt P.</> ".git" == d = return False-	| otherwise = doesFileExist (fromRawFilePath (wt P.</> ".git"))+	| wt </> ".git" == d = return False+	| otherwise = doesFileExist (fromRawFilePath (wt </> ".git")) needsGitLinkFixup _ = return False
Annex/GitOverlay.hs view
@@ -90,8 +90,8 @@ withWorkTreeRelated d a = withAltRepo modrepo unmodrepo (const a)   where 	modrepo g = liftIO $ do-		g' <- addGitEnv g "GIT_COMMON_DIR"-			=<< absPath (fromRawFilePath (localGitDir g))+		g' <- addGitEnv g "GIT_COMMON_DIR" . fromRawFilePath+			=<< absPath (localGitDir g) 		g'' <- addGitEnv g' "GIT_DIR" d 		return (g'' { gitEnvOverridesGitDir = True }, ()) 	unmodrepo g g' = g'
Annex/HashObject.hs view
@@ -33,7 +33,7 @@ 		Annex.changeState $ \s -> s { Annex.hashobjecthandle = Nothing } 		return () -hashFile :: FilePath -> Annex Sha+hashFile :: RawFilePath -> Annex Sha hashFile f = do 	h <- hashObjectHandle 	liftIO $ Git.HashObject.hashFile h f
Annex/Import.hs view
@@ -271,7 +271,7 @@ 	mktreeitem (loc, v) = case v of 		Right k -> do 			relf <- fromRepo $ fromTopFilePath topf-			symlink <- calcRepo $ gitAnnexLink (fromRawFilePath relf) k+			symlink <- calcRepo $ gitAnnexLink relf k 			linksha <- hashSymlink symlink 			return $ TreeItem treepath (fromTreeItemType TreeSymlink) linksha 		Left sha -> @@ -393,7 +393,7 @@ 	 	importordownload cidmap db (loc, (cid, sz)) largematcher= do 		f <- locworktreefile loc-		matcher <- largematcher (fromRawFilePath f)+		matcher <- largematcher f 		-- When importing a key is supported, always use it rather 		-- than downloading and retrieving a key, to avoid 		-- generating trees with different keys for the same content.@@ -457,7 +457,7 @@ 			let af = AssociatedFile (Just f) 			let downloader p' tmpfile = do 				k' <- Remote.retrieveExportWithContentIdentifier-					ia loc cid tmpfile +					ia loc cid (fromRawFilePath tmpfile) 					(pure k) 					(combineMeterUpdate p' p) 				ok <- moveAnnex k' tmpfile@@ -475,7 +475,7 @@ 	doimportsmall cidmap db loc cid sz p = do 		let downloader tmpfile = do 			k <- Remote.retrieveExportWithContentIdentifier-				ia loc cid tmpfile+				ia loc cid (fromRawFilePath tmpfile) 				(mkkey tmpfile) 				p 			case keyGitSha k of@@ -498,7 +498,7 @@ 		let af = AssociatedFile (Just f) 		let downloader tmpfile p = do 			k <- Remote.retrieveExportWithContentIdentifier-				ia loc cid tmpfile +				ia loc cid (fromRawFilePath tmpfile) 				(mkkey tmpfile) 				p 			case keyGitSha k of@@ -530,15 +530,15 @@ 		mkkey tmpfile = do 			let mi = MatchingFile FileInfo 				{ matchFile = f-				, contentFile = Just (toRawFilePath tmpfile)+				, contentFile = Just tmpfile 				} 			islargefile <- checkMatcher' matcher mi mempty 			if islargefile 				then do-					backend <- chooseBackend (fromRawFilePath f)+					backend <- chooseBackend f 					let ks = KeySource 						{ keyFilename = f-						, contentLocation = toRawFilePath tmpfile+						, contentLocation = tmpfile 						, inodeCache = Nothing 						} 					fst <$> genKey ks nullMeterUpdate backend@@ -671,7 +671,7 @@ notIgnoredImportLocation :: ImportTreeConfig -> CheckGitIgnore -> ImportLocation -> Annex Bool notIgnoredImportLocation importtreeconfig ci loc = not <$> checkIgnored ci f   where-	f = fromRawFilePath $ case importtreeconfig of+	f = case importtreeconfig of 		ImportSubTree dir _ -> 			getTopFilePath dir P.</> fromImportLocation loc 		ImportTree ->
Annex/Ingest.hs view
@@ -21,6 +21,7 @@ 	CheckGitIgnore(..), 	gitAddParams, 	addAnnexedFile,+	addingExistingLink, ) where  import Annex.Common@@ -61,7 +62,7 @@ data LockDownConfig = LockDownConfig 	{ lockingFile :: Bool 	-- ^ write bit removed during lock down-	, hardlinkFileTmpDir :: Maybe FilePath+	, hardlinkFileTmpDir :: Maybe RawFilePath 	-- ^ hard link to temp directory 	} 	deriving (Show)@@ -98,7 +99,7 @@ 	nohardlink = withTSDelta $ liftIO . nohardlink'  	nohardlink' delta = do-		cache <- genInodeCache (toRawFilePath file) delta+		cache <- genInodeCache file' delta 		return $ LockedDown cfg $ KeySource 			{ keyFilename = file' 			, contentLocation = file'@@ -107,12 +108,12 @@ 	 	withhardlink tmpdir = do 		when (lockingFile cfg) $-			freezeContent file+			freezeContent file' 		withTSDelta $ \delta -> liftIO $ do-			(tmpfile, h) <- openTempFile tmpdir $+			(tmpfile, h) <- openTempFile (fromRawFilePath tmpdir) $ 				relatedTemplate $ "ingest-" ++ takeFileName file 			hClose h-			nukeFile tmpfile+			removeWhenExistsWith removeLink tmpfile 			withhardlink' delta tmpfile 				`catchIO` const (nohardlink' delta) @@ -139,7 +140,7 @@ 		Just k -> do 			let f = keyFilename source 			if lockingFile cfg-				then addLink ci (fromRawFilePath f) k mic+				then addLink ci f k mic 				else do 					mode <- liftIO $ catchMaybeIO $ 						fileMode <$> R.getFileStatus (contentLocation source)@@ -157,14 +158,14 @@ 	k <- case mk of 		Nothing -> do 			backend <- maybe-				(chooseBackend $ fromRawFilePath $ keyFilename source)+				(chooseBackend $ keyFilename source) 				(return . Just) 				preferredbackend 			fst <$> genKey source meterupdate backend 		Just k -> return k 	let src = contentLocation source 	ms <- liftIO $ catchMaybeIO $ R.getFileStatus src-	mcache <- maybe (pure Nothing) (liftIO . toInodeCache delta (fromRawFilePath src)) ms+	mcache <- maybe (pure Nothing) (liftIO . toInodeCache delta src) ms 	case (mcache, inodeCache source) of 		(_, Nothing) -> go k mcache ms 		(Just newc, Just c) | compareStrong c newc -> go k mcache ms@@ -176,12 +177,12 @@ 	go _ _ Nothing = failure "failed to generate a key"  	golocked key mcache s =-		tryNonAsync (moveAnnex key $ fromRawFilePath $ contentLocation source) >>= \case+		tryNonAsync (moveAnnex key $ contentLocation source) >>= \case 			Right True -> do 				populateAssociatedFiles key source restage 				success key mcache s		 			Right False -> giveup "failed to add content to annex"-			Left e -> restoreFile (fromRawFilePath $ keyFilename source) key e+			Left e -> restoreFile (keyFilename source) key e  	gounlocked key (Just cache) s = do 		-- Remove temp directory hard link first because@@ -189,7 +190,7 @@ 		-- already has a hard link. 		cleanCruft source 		cleanOldKeys (keyFilename source) key-		linkToAnnex key (fromRawFilePath $ keyFilename source) (Just cache) >>= \case+		linkToAnnex key (keyFilename source) (Just cache) >>= \case 			LinkAnnexFailed -> failure "failed to link to annex" 			_ -> do 				finishIngestUnlocked' key source restage@@ -229,7 +230,7 @@  cleanCruft :: KeySource -> Annex () cleanCruft source = when (contentLocation source /= keyFilename source) $-	liftIO $ nukeFile $ fromRawFilePath $ contentLocation source+	liftIO $ removeWhenExistsWith R.removeLink $ contentLocation source  -- If a worktree file was was hard linked to an annex object before, -- modifying the file would have caused the object to have the wrong@@ -254,28 +255,28 @@ 				-- so no need for any recovery. 				(f:_) -> do 					ic <- withTSDelta (liftIO . genInodeCache f)-					void $ linkToAnnex key (fromRawFilePath f) ic+					void $ linkToAnnex key f ic 				_ -> logStatus key InfoMissing  {- On error, put the file back so it doesn't seem to have vanished.  - This can be called before or after the symlink is in place. -}-restoreFile :: FilePath -> Key -> SomeException -> Annex a+restoreFile :: RawFilePath -> Key -> SomeException -> Annex a restoreFile file key e = do 	whenM (inAnnex key) $ do-		liftIO $ nukeFile file+		liftIO $ removeWhenExistsWith R.removeLink file 		-- The key could be used by other files too, so leave the 		-- content in the annex, and make a copy back to the file. 		obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)-		unlessM (liftIO $ copyFileExternal CopyTimeStamps obj file) $-			warning $ "Unable to restore content of " ++ file ++ "; it should be located in " ++ obj+		unlessM (liftIO $ copyFileExternal CopyTimeStamps obj (fromRawFilePath file)) $+			warning $ "Unable to restore content of " ++ fromRawFilePath file ++ "; it should be located in " ++ obj 		thawContent file 	throwM e  {- Creates the symlink to the annexed content, returns the link target. -}-makeLink :: FilePath -> Key -> Maybe InodeCache -> Annex String+makeLink :: RawFilePath -> Key -> Maybe InodeCache -> Annex LinkTarget makeLink file key mcache = flip catchNonAsync (restoreFile file key) $ do 	l <- calcRepo $ gitAnnexLink file key-	replaceWorkTreeFile file $ makeAnnexLink l . toRawFilePath+	replaceWorkTreeFile file' $ makeAnnexLink l . toRawFilePath  	-- touch symlink to have same time as the original file, 	-- as provided in the InodeCache@@ -284,6 +285,8 @@ 		Nothing -> noop  	return l+  where+	file' = fromRawFilePath file  {- Creates the symlink to the annexed content, and stages it in git.  -@@ -294,15 +297,15 @@  - Also, using git add allows it to skip gitignored files, unless forced  - to include them.  -}-addLink :: CheckGitIgnore -> FilePath -> Key -> Maybe InodeCache -> Annex ()+addLink :: CheckGitIgnore -> RawFilePath -> Key -> Maybe InodeCache -> Annex () addLink ci file key mcache = ifM (coreSymlinks <$> Annex.getGitConfig) 	( do 		_ <- makeLink file key mcache 		ps <- gitAddParams ci-		Annex.Queue.addCommand "add" (ps++[Param "--"]) [file]+		Annex.Queue.addCommand "add" (ps++[Param "--"]) [fromRawFilePath file] 	, do 		l <- makeLink file key mcache-		addAnnexLink l (toRawFilePath file)+		addAnnexLink l file 	)  {- Parameters to pass to git add, forcing addition of ignored files.@@ -339,15 +342,15 @@  -  - When the content of the key is not accepted into the annex, returns False.  -}-addAnnexedFile :: CheckGitIgnore -> AddUnlockedMatcher -> FilePath -> Key -> Maybe FilePath -> Annex Bool+addAnnexedFile :: CheckGitIgnore -> AddUnlockedMatcher -> RawFilePath -> Key -> Maybe RawFilePath -> Annex Bool addAnnexedFile ci matcher file key mtmp = ifM (addUnlocked matcher mi) 	( do 		mode <- maybe 			(pure Nothing)-			(\tmp -> liftIO $ catchMaybeIO $ fileMode <$> getFileStatus tmp)+			(\tmp -> liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus tmp) 			mtmp-		stagePointerFile file' mode =<< hashPointerFile key-		Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file')+		stagePointerFile file mode =<< hashPointerFile key+		Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file) 		case mtmp of 			Just tmp -> ifM (moveAnnex key tmp) 				( linkunlocked mode >> return True@@ -366,13 +369,13 @@   where 	mi = case mtmp of 		Just tmp -> MatchingFile $ FileInfo-			{ contentFile = Just (toRawFilePath tmp)-			, matchFile = file'+			{ contentFile = Just tmp+			, matchFile = file 			} 		-- Provide as much info as we can without access to the 		-- file's content. 		Nothing -> MatchingInfo $ ProvidedInfo-			{ providedFilePath = file'+			{ providedFilePath = file 			, providedKey = Just key 			, providedFileSize = fromMaybe 0 $ 				keySize `fromKey` key@@ -381,9 +384,23 @@ 			} 	 	linkunlocked mode = linkFromAnnex key file mode >>= \case-		LinkAnnexFailed -> liftIO $-			writePointerFile file' key mode+		LinkAnnexFailed -> liftIO $ writepointer mode 		_ -> return ()-	writepointer mode = liftIO $ writePointerFile file' key mode+	+	writepointer mode = liftIO $ writePointerFile file key mode -	file' = toRawFilePath file+{- Use with actions that add an already existing annex symlink or pointer+ - file. The warning avoids a confusing situation where the file got copied+ - from another git-annex repo, probably by accident. -}+addingExistingLink :: RawFilePath -> Key -> Annex a -> Annex a+addingExistingLink f k a = do+	unlessM (isKnownKey k <||> inAnnex k) $ do+		islink <- isJust <$> isAnnexLink f+		warning $ unwords+			[ fromRawFilePath f+			, "is a git-annex"+			, if islink then "symlink." else "pointer file."+			, "Its content is not available in this repository."+			, "(Maybe " ++ fromRawFilePath f ++ " was copied from another repository?)"+			]+	a
Annex/Init.hs view
@@ -50,6 +50,7 @@ import Annex.Tmp import Utility.UserInfo import Utility.ThreadScheduler+import qualified Utility.RawFilePath as R #ifndef mingw32_HOST_OS import Annex.Perms import Utility.FileMode@@ -59,6 +60,7 @@ #endif  import qualified Data.Map as M+import qualified System.FilePath.ByteString as P import Control.Concurrent.Async  checkCanInitialize :: Annex a -> Annex a@@ -79,8 +81,8 @@ genDescription :: Maybe String -> Annex UUIDDesc genDescription (Just d) = return $ UUIDDesc $ encodeBS d genDescription Nothing = do-	reldir <- liftIO . relHome-		=<< liftIO . absPath . fromRawFilePath+	reldir <- liftIO . relHome . fromRawFilePath+		=<< liftIO . absPath 		=<< fromRepo Git.repoPath 	hostname <- fromMaybe "" <$> liftIO getHostname 	let at = if null hostname then "" else "@"@@ -194,24 +196,24 @@ 	mapM_ warning warnings 	return r -probeCrippledFileSystem' :: FilePath -> IO (Bool, [String])+probeCrippledFileSystem' :: RawFilePath -> IO (Bool, [String]) #ifdef mingw32_HOST_OS probeCrippledFileSystem' _ = return (True, []) #else probeCrippledFileSystem' tmp = do-	let f = tmp </> "gaprobe"+	let f = fromRawFilePath (tmp P.</> "gaprobe") 	writeFile f "" 	r <- probe f-	void $ tryIO $ allowWrite f+	void $ tryIO $ allowWrite (toRawFilePath f) 	removeFile f 	return r   where 	probe f = catchDefaultIO (True, []) $ do 		let f2 = f ++ "2"-		nukeFile f2+		removeWhenExistsWith removeLink f2 		createSymbolicLink f f2-		nukeFile f2-		preventWrite f+		removeWhenExistsWith removeLink f2+		preventWrite (toRawFilePath f) 		-- Should be unable to write to the file, unless 		-- running as root, but some crippled 		-- filesystems ignore write bit removals.@@ -246,18 +248,18 @@ probeLockSupport = return True #else probeLockSupport = withEventuallyCleanedOtherTmp $ \tmp -> do-	let f = tmp </> "lockprobe"+	let f = tmp P.</> "lockprobe" 	mode <- annexFileMode 	liftIO $ withAsync warnstall (const (go f mode))   where 	go f mode = do-		nukeFile f+		removeWhenExistsWith R.removeLink f 		let locktest = bracket 			(Posix.lockExclusive (Just mode) f) 			Posix.dropLock 			(const noop) 		ok <- isRight <$> tryNonAsync locktest-		nukeFile f+		removeWhenExistsWith R.removeLink f 		return ok 	 	warnstall = do@@ -272,17 +274,17 @@ 	return False #else 	withEventuallyCleanedOtherTmp $ \tmp -> do-		let f = tmp </> "gaprobe"-		let f2 = tmp </> "gaprobe2"+		let f = tmp P.</> "gaprobe"+		let f2 = tmp P.</> "gaprobe2" 		liftIO $ do-			nukeFile f-			nukeFile f2+			removeWhenExistsWith R.removeLink f+			removeWhenExistsWith R.removeLink f2 			ms <- tryIO $ do-				createNamedPipe f ownerReadMode-				createLink f f2-				getFileStatus f-			nukeFile f-			nukeFile f2+				createNamedPipe (fromRawFilePath f) ownerReadMode+				R.createLink f f2+				R.getFileStatus f+			removeWhenExistsWith R.removeLink f+			removeWhenExistsWith R.removeLink f2 			return $ either (const False) isNamedPipe ms #endif 
Annex/InodeSentinal.hs view
@@ -78,13 +78,14 @@ createInodeSentinalFile evenwithobjects =  	unlessM (alreadyexists <||> hasobjects) $ do 		s <- annexSentinalFile-		createAnnexDirectory (parentDir (fromRawFilePath (sentinalFile s)))+		createAnnexDirectory (parentDir (sentinalFile s)) 		liftIO $ writeSentinalFile s   where 	alreadyexists = liftIO. sentinalFileExists =<< annexSentinalFile 	hasobjects 		| evenwithobjects = pure False-		| otherwise = liftIO . doesDirectoryExist =<< fromRepo gitAnnexObjectDir+		| otherwise = liftIO . doesDirectoryExist . fromRawFilePath+			=<< fromRepo gitAnnexObjectDir  annexSentinalFile :: Annex SentinalFile annexSentinalFile = do
Annex/Journal.hs view
@@ -50,11 +50,11 @@ setJournalFile _jl file content = withOtherTmp $ \tmp -> do 	createAnnexDirectory =<< fromRepo gitAnnexJournalDir 	-- journal file is written atomically-	jfile <- fromRawFilePath <$> fromRepo (journalFile file)-	let tmpfile = tmp </> takeFileName jfile+	jfile <- fromRepo (journalFile file)+	let tmpfile = fromRawFilePath (tmp P.</> P.takeFileName jfile) 	liftIO $ do 		withFile tmpfile WriteMode $ \h -> writeJournalHandle h content-		moveFile tmpfile jfile+		moveFile tmpfile (fromRawFilePath jfile)  {- Gets any journalled content for a file in the branch. -} getJournalFile :: JournalLocked -> RawFilePath -> Annex (Maybe L.ByteString)@@ -82,19 +82,19 @@ getJournalledFilesStale = do 	g <- gitRepo 	fs <- liftIO $ catchDefaultIO [] $-		getDirectoryContents $ gitAnnexJournalDir g+		getDirectoryContents $ fromRawFilePath $ gitAnnexJournalDir g 	return $ filter (`notElem` [".", ".."]) $ 		map (fromRawFilePath . fileJournal . toRawFilePath) fs  withJournalHandle :: (DirectoryHandle -> IO a) -> Annex a withJournalHandle a = do-	d <- fromRepo gitAnnexJournalDir+	d <- fromRawFilePath <$> fromRepo gitAnnexJournalDir 	bracketIO (openDirectory d) closeDirectory (liftIO . a)  {- Checks if there are changes in the journal. -} journalDirty :: Annex Bool journalDirty = do-	d <- fromRepo gitAnnexJournalDir+	d <- fromRawFilePath <$> fromRepo gitAnnexJournalDir 	liftIO $  		(not <$> isDirectoryEmpty d) 			`catchIO` (const $ doesDirectoryExist d)
Annex/Link.hs view
@@ -42,7 +42,7 @@ import qualified Data.ByteString.Lazy as L import qualified System.FilePath.ByteString as P -type LinkTarget = String+type LinkTarget = S.ByteString  {- Checks if a file is a link to a key. -} isAnnexLink :: RawFilePath -> Annex (Maybe Key)@@ -56,7 +56,7 @@  - Returns Nothing if the file is not a symlink, or not a link to annex  - content.  -}-getAnnexLinkTarget :: RawFilePath -> Annex (Maybe S.ByteString)+getAnnexLinkTarget :: RawFilePath -> Annex (Maybe LinkTarget) getAnnexLinkTarget f = getAnnexLinkTarget' f 	=<< (coreSymlinks <$> Annex.getGitConfig) @@ -107,9 +107,9 @@ makeGitLink :: LinkTarget -> RawFilePath -> Annex () makeGitLink linktarget file = ifM (coreSymlinks <$> Annex.getGitConfig) 	( liftIO $ do-		void $ tryIO $ removeFile (fromRawFilePath file)-		createSymbolicLink linktarget (fromRawFilePath file)-	, liftIO $ writeFile (fromRawFilePath file) linktarget+		void $ tryIO $ R.removeLink file+		R.createSymbolicLink linktarget file+	, liftIO $ S.writeFile (fromRawFilePath file) linktarget 	)  {- Creates a link on disk, and additionally stages it in git. -}@@ -120,13 +120,13 @@  {- Injects a symlink target into git, returning its Sha. -} hashSymlink :: LinkTarget -> Annex Sha-hashSymlink = hashBlob . toInternalGitPath . toRawFilePath+hashSymlink = hashBlob . toInternalGitPath  {- Stages a symlink to an annexed object, using a Sha of its target. -} stageSymlink :: RawFilePath -> Sha -> Annex () stageSymlink file sha = 	Annex.Queue.addUpdateIndex =<<-		inRepo (Git.UpdateIndex.stageSymlink (fromRawFilePath file) sha)+		inRepo (Git.UpdateIndex.stageSymlink file sha)  {- Injects a pointer file content into git, returning its Sha. -} hashPointerFile :: Key -> Annex Sha@@ -187,7 +187,7 @@ 		-- update-index is documented as picky about "./file" and it 		-- fails on "../../repo/path/file" when cwd is not in the repo  		-- being acted on. Avoid these problems with an absolute path.-		absf <- liftIO $ absPath $ fromRawFilePath f+		absf <- liftIO $ absPath f 		Annex.Queue.addInternalAction runner [(absf, isunmodified tsd)]   where 	isunmodified tsd = genInodeCache f tsd >>= return . \case@@ -203,7 +203,7 @@ 	runner :: Git.Queue.InternalActionRunner Annex 	runner = Git.Queue.InternalActionRunner "restagePointerFile" $ \r l -> do 		realindex <- liftIO $ Git.Index.currentIndexFile r-		let lock = Git.Index.indexFileLock realindex+		let lock = fromRawFilePath (Git.Index.indexFileLock realindex) 		    lockindex = liftIO $ catchMaybeIO $ Git.LockFile.openLock' lock 		    unlockindex = liftIO . maybe noop Git.LockFile.closeLock 		    showwarning = warning $ unableToRestage Nothing@@ -211,8 +211,8 @@ 		    go (Just _) = withTmpDirIn (fromRawFilePath $ Git.localGitDir r) "annexindex" $ \tmpdir -> do 			let tmpindex = tmpdir </> "index" 			let updatetmpindex = do-				r' <- liftIO $ Git.Env.addGitEnv r Git.Index.indexEnv -					=<< Git.Index.indexEnvVal tmpindex+				r' <- liftIO $ Git.Env.addGitEnv r Git.Index.indexEnv+					=<< Git.Index.indexEnvVal (toRawFilePath tmpindex) 				-- Avoid git warning about CRLF munging. 				let r'' = r' { gitGlobalOpts = gitGlobalOpts r' ++ 					[ Param "-c"@@ -224,9 +224,9 @@ 							whenM checkunmodified $ 								feed f' 			let replaceindex = catchBoolIO $ do-				moveFile tmpindex realindex+				moveFile tmpindex (fromRawFilePath realindex) 				return True-			ok <- liftIO (createLinkOrCopy realindex tmpindex)+			ok <- liftIO (createLinkOrCopy (fromRawFilePath realindex) tmpindex) 				<&&> updatetmpindex 				<&&> liftIO replaceindex 			unless ok showwarning
Annex/Locations.hs view
@@ -1,6 +1,6 @@ {- git-annex file locations  -- - Copyright 2010-2019 Joey Hess <id@joeyh.name>+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -20,8 +20,6 @@ 	gitAnnexLink, 	gitAnnexLinkCanonical, 	gitAnnexContentLock,-	gitAnnexMapping,-	gitAnnexInodeCache, 	gitAnnexInodeSentinal, 	gitAnnexInodeSentinalCache, 	annexLocations,@@ -68,7 +66,6 @@ 	gitAnnexJournalDir', 	gitAnnexJournalLock, 	gitAnnexGitQueueLock,-	gitAnnexMergeLock, 	gitAnnexIndex, 	gitAnnexIndexStatus, 	gitAnnexViewIndex,@@ -161,9 +158,6 @@  -  - When the file is not present, returns the location where the file should  - be stored.- -- - This does not take direct mode into account, so in direct mode it is not- - the actual location of the file's content.  -} gitAnnexLocation :: Key -> Git.Repo -> GitConfig -> IO RawFilePath gitAnnexLocation key r config = gitAnnexLocation' key r config@@ -199,32 +193,27 @@ 	check [] = error "internal"  {- Calculates a symlink target to link a file to an annexed object. -}-gitAnnexLink :: FilePath -> Key -> Git.Repo -> GitConfig -> IO FilePath+gitAnnexLink :: RawFilePath -> Key -> Git.Repo -> GitConfig -> IO RawFilePath gitAnnexLink file key r config = do-	currdir <- getCurrentDirectory+	currdir <- R.getCurrentDirectory 	let absfile = absNormPathUnix currdir file 	let gitdir = getgitdir currdir 	loc <- gitAnnexLocation' key r config False False (\_ -> return True) gitdir-	fromRawFilePath . toInternalGitPath . toRawFilePath-		<$> relPathDirToFile (parentDir absfile) (fromRawFilePath loc)+	toInternalGitPath <$> relPathDirToFile (parentDir absfile) loc   where 	getgitdir currdir 		{- This special case is for git submodules on filesystems not 		 - supporting symlinks; generate link target that will 		 - work portably. -} 		| not (coreSymlinks config) && needsSubmoduleFixup r =-			toRawFilePath $-				absNormPathUnix currdir $ fromRawFilePath $-					Git.repoPath r P.</> ".git"+			absNormPathUnix currdir (Git.repoPath r P.</> ".git") 		| otherwise = Git.localGitDir r-	absNormPathUnix d p = fromRawFilePath $ toInternalGitPath $ toRawFilePath $-		absPathFrom-			(fromRawFilePath $ toInternalGitPath $ toRawFilePath d)-			(fromRawFilePath $ toInternalGitPath $ toRawFilePath p)+	absNormPathUnix d p = toInternalGitPath $+		absPathFrom (toInternalGitPath d) (toInternalGitPath p)  {- Calculates a symlink target as would be used in a typical git  - repository, with .git in the top of the work tree. -}-gitAnnexLinkCanonical :: FilePath -> Key -> Git.Repo -> GitConfig -> IO FilePath+gitAnnexLinkCanonical :: RawFilePath -> Key -> Git.Repo -> GitConfig -> IO RawFilePath gitAnnexLinkCanonical file key r config = gitAnnexLink file key r' config'   where 	r' = case r of@@ -237,25 +226,10 @@ 		}  {- File used to lock a key's content. -}-gitAnnexContentLock :: Key -> Git.Repo -> GitConfig -> IO FilePath+gitAnnexContentLock :: Key -> Git.Repo -> GitConfig -> IO RawFilePath gitAnnexContentLock key r config = do 	loc <- gitAnnexLocation key r config-	return $ fromRawFilePath loc ++ ".lck"--{- File that maps from a key to the file(s) in the git repository.- - Used in direct mode. -}-gitAnnexMapping :: Key -> Git.Repo -> GitConfig -> IO FilePath-gitAnnexMapping key r config = do-	loc <- gitAnnexLocation key r config-	return $ fromRawFilePath loc ++ ".map"--{- File that caches information about a key's content, used to determine- - if a file has changed.- - Used in direct mode. -}-gitAnnexInodeCache :: Key -> Git.Repo -> GitConfig -> IO FilePath-gitAnnexInodeCache key r config = do-	loc <- gitAnnexLocation key r config-	return $ fromRawFilePath loc ++ ".cache"+	return $ loc <> ".lck"  gitAnnexInodeSentinal :: Git.Repo -> RawFilePath gitAnnexInodeSentinal r = gitAnnexDir r P.</> "sentinal"@@ -268,41 +242,38 @@ gitAnnexDir r = P.addTrailingPathSeparator $ Git.localGitDir r P.</> annexDir  {- The part of the annex directory where file contents are stored. -}-gitAnnexObjectDir :: Git.Repo -> FilePath-gitAnnexObjectDir r = fromRawFilePath $ -	P.addTrailingPathSeparator $ Git.localGitDir r P.</> objectDir'+gitAnnexObjectDir :: Git.Repo -> RawFilePath+gitAnnexObjectDir r = P.addTrailingPathSeparator $+	Git.localGitDir r P.</> objectDir'  {- .git/annex/tmp/ is used for temp files for key's contents -}-gitAnnexTmpObjectDir :: Git.Repo -> FilePath-gitAnnexTmpObjectDir = fromRawFilePath . gitAnnexTmpObjectDir'--gitAnnexTmpObjectDir' :: Git.Repo -> RawFilePath-gitAnnexTmpObjectDir' r = P.addTrailingPathSeparator $ gitAnnexDir r P.</> "tmp"+gitAnnexTmpObjectDir :: Git.Repo -> RawFilePath+gitAnnexTmpObjectDir r = P.addTrailingPathSeparator $+	gitAnnexDir r P.</> "tmp"  {- .git/annex/othertmp/ is used for other temp files -}-gitAnnexTmpOtherDir :: Git.Repo -> FilePath-gitAnnexTmpOtherDir r = fromRawFilePath $-	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "othertmp"+gitAnnexTmpOtherDir :: Git.Repo -> RawFilePath+gitAnnexTmpOtherDir r = P.addTrailingPathSeparator $+	gitAnnexDir r P.</> "othertmp"  {- Lock file for gitAnnexTmpOtherDir. -}-gitAnnexTmpOtherLock :: Git.Repo -> FilePath-gitAnnexTmpOtherLock r = fromRawFilePath $ gitAnnexDir r P.</> "othertmp.lck"+gitAnnexTmpOtherLock :: Git.Repo -> RawFilePath+gitAnnexTmpOtherLock r = gitAnnexDir r P.</> "othertmp.lck"  {- .git/annex/misctmp/ was used by old versions of git-annex and is still  - used during initialization -}-gitAnnexTmpOtherDirOld :: Git.Repo -> FilePath-gitAnnexTmpOtherDirOld r = fromRawFilePath $ -	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "misctmp"+gitAnnexTmpOtherDirOld :: Git.Repo -> RawFilePath+gitAnnexTmpOtherDirOld r = P.addTrailingPathSeparator $ +	gitAnnexDir r P.</> "misctmp"  {- .git/annex/watchtmp/ is used by the watcher and assistant -}-gitAnnexTmpWatcherDir :: Git.Repo -> FilePath-gitAnnexTmpWatcherDir r = fromRawFilePath $-	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "watchtmp"+gitAnnexTmpWatcherDir :: Git.Repo -> RawFilePath+gitAnnexTmpWatcherDir r = P.addTrailingPathSeparator $+	gitAnnexDir r P.</> "watchtmp"  {- The temp file to use for a given key's content. -}-gitAnnexTmpObjectLocation :: Key -> Git.Repo -> FilePath-gitAnnexTmpObjectLocation key r = fromRawFilePath $-	gitAnnexTmpObjectDir' r P.</> keyFile key+gitAnnexTmpObjectLocation :: Key -> Git.Repo -> RawFilePath+gitAnnexTmpObjectLocation key r = gitAnnexTmpObjectDir r P.</> keyFile key  {- Given a temp file such as gitAnnexTmpObjectLocation, makes a name for a  - subdirectory in the same location, that can be used as a work area@@ -311,127 +282,122 @@  - There are ordering requirements for creating these directories;  - use Annex.Content.withTmpWorkDir to set them up.  -}-gitAnnexTmpWorkDir :: FilePath -> FilePath+gitAnnexTmpWorkDir :: RawFilePath -> RawFilePath gitAnnexTmpWorkDir p =-	let (dir, f) = splitFileName p+	let (dir, f) = P.splitFileName p 	-- Using a prefix avoids name conflict with any other keys.-	in dir </> "work." ++ f+	in dir P.</> "work." <> f  {- .git/annex/bad/ is used for bad files found during fsck -}-gitAnnexBadDir :: Git.Repo -> FilePath-gitAnnexBadDir r = fromRawFilePath $-	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "bad"+gitAnnexBadDir :: Git.Repo -> RawFilePath+gitAnnexBadDir r = P.addTrailingPathSeparator $ gitAnnexDir r P.</> "bad"  {- The bad file to use for a given key. -}-gitAnnexBadLocation :: Key -> Git.Repo -> FilePath-gitAnnexBadLocation key r = gitAnnexBadDir r </> fromRawFilePath (keyFile key)+gitAnnexBadLocation :: Key -> Git.Repo -> RawFilePath+gitAnnexBadLocation key r = gitAnnexBadDir r P.</> keyFile key  {- .git/annex/foounused is used to number possibly unused keys -}-gitAnnexUnusedLog :: FilePath -> Git.Repo -> FilePath-gitAnnexUnusedLog prefix r =-	fromRawFilePath (gitAnnexDir r) </> (prefix ++ "unused")+gitAnnexUnusedLog :: RawFilePath -> Git.Repo -> RawFilePath+gitAnnexUnusedLog prefix r = gitAnnexDir r P.</> (prefix <> "unused")  {- .git/annex/keysdb/ contains a database of information about keys. -}-gitAnnexKeysDb :: Git.Repo -> FilePath-gitAnnexKeysDb r = fromRawFilePath $ gitAnnexDir r P.</> "keysdb"+gitAnnexKeysDb :: Git.Repo -> RawFilePath+gitAnnexKeysDb r = gitAnnexDir r P.</> "keysdb"  {- Lock file for the keys database. -}-gitAnnexKeysDbLock :: Git.Repo -> FilePath-gitAnnexKeysDbLock r = gitAnnexKeysDb r ++ ".lck"+gitAnnexKeysDbLock :: Git.Repo -> RawFilePath+gitAnnexKeysDbLock r = gitAnnexKeysDb r <> ".lck"  {- Contains the stat of the last index file that was  - reconciled with the keys database. -}-gitAnnexKeysDbIndexCache :: Git.Repo -> FilePath-gitAnnexKeysDbIndexCache r = gitAnnexKeysDb r ++ ".cache"+gitAnnexKeysDbIndexCache :: Git.Repo -> RawFilePath+gitAnnexKeysDbIndexCache r = gitAnnexKeysDb r <> ".cache"  {- .git/annex/fsck/uuid/ is used to store information about incremental  - fscks. -}-gitAnnexFsckDir :: UUID -> Git.Repo -> FilePath-gitAnnexFsckDir u r = fromRawFilePath $-	gitAnnexDir r P.</> "fsck" P.</> fromUUID u+gitAnnexFsckDir :: UUID -> Git.Repo -> RawFilePath+gitAnnexFsckDir u r = gitAnnexDir r P.</> "fsck" P.</> fromUUID u  {- used to store information about incremental fscks. -}-gitAnnexFsckState :: UUID -> Git.Repo -> FilePath-gitAnnexFsckState u r = gitAnnexFsckDir u r </> "state"+gitAnnexFsckState :: UUID -> Git.Repo -> RawFilePath+gitAnnexFsckState u r = gitAnnexFsckDir u r P.</> "state"  {- Directory containing database used to record fsck info. -}-gitAnnexFsckDbDir :: UUID -> Git.Repo -> FilePath-gitAnnexFsckDbDir u r = gitAnnexFsckDir u r </> "fsckdb"+gitAnnexFsckDbDir :: UUID -> Git.Repo -> RawFilePath+gitAnnexFsckDbDir u r = gitAnnexFsckDir u r P.</> "fsckdb"  {- Directory containing old database used to record fsck info. -}-gitAnnexFsckDbDirOld :: UUID -> Git.Repo -> FilePath-gitAnnexFsckDbDirOld u r = gitAnnexFsckDir u r </> "db"+gitAnnexFsckDbDirOld :: UUID -> Git.Repo -> RawFilePath+gitAnnexFsckDbDirOld u r = gitAnnexFsckDir u r P.</> "db"  {- Lock file for the fsck database. -}-gitAnnexFsckDbLock :: UUID -> Git.Repo -> FilePath-gitAnnexFsckDbLock u r = gitAnnexFsckDir u r </> "fsck.lck"+gitAnnexFsckDbLock :: UUID -> Git.Repo -> RawFilePath+gitAnnexFsckDbLock u r = gitAnnexFsckDir u r P.</> "fsck.lck"  {- .git/annex/fsckresults/uuid is used to store results of git fscks -}-gitAnnexFsckResultsLog :: UUID -> Git.Repo -> FilePath-gitAnnexFsckResultsLog u r = fromRawFilePath $ +gitAnnexFsckResultsLog :: UUID -> Git.Repo -> RawFilePath+gitAnnexFsckResultsLog u r =  	gitAnnexDir r P.</> "fsckresults" P.</> fromUUID u  {- .git/annex/smudge.log is used to log smudges worktree files that need to  - be updated. -}-gitAnnexSmudgeLog :: Git.Repo -> FilePath-gitAnnexSmudgeLog r = fromRawFilePath $ gitAnnexDir r P.</> "smudge.log"+gitAnnexSmudgeLog :: Git.Repo -> RawFilePath+gitAnnexSmudgeLog r = gitAnnexDir r P.</> "smudge.log" -gitAnnexSmudgeLock :: Git.Repo -> FilePath-gitAnnexSmudgeLock r = fromRawFilePath $ gitAnnexDir r P.</> "smudge.lck"+gitAnnexSmudgeLock :: Git.Repo -> RawFilePath+gitAnnexSmudgeLock r = gitAnnexDir r P.</> "smudge.lck"  {- .git/annex/move.log is used to log moves that are in progress,  - to better support resuming an interrupted move. -}-gitAnnexMoveLog :: Git.Repo -> FilePath-gitAnnexMoveLog r = fromRawFilePath $ gitAnnexDir r P.</> "move.log"+gitAnnexMoveLog :: Git.Repo -> RawFilePath+gitAnnexMoveLog r = gitAnnexDir r P.</> "move.log" -gitAnnexMoveLock :: Git.Repo -> FilePath-gitAnnexMoveLock r = fromRawFilePath $ gitAnnexDir r P.</> "move.lck"+gitAnnexMoveLock :: Git.Repo -> RawFilePath+gitAnnexMoveLock r = gitAnnexDir r P.</> "move.lck"  {- .git/annex/export/ is used to store information about  - exports to special remotes. -}-gitAnnexExportDir :: Git.Repo -> FilePath-gitAnnexExportDir r = fromRawFilePath $ gitAnnexDir r P.</> "export"+gitAnnexExportDir :: Git.Repo -> RawFilePath+gitAnnexExportDir r = gitAnnexDir r P.</> "export"  {- Directory containing database used to record export info. -}-gitAnnexExportDbDir :: UUID -> Git.Repo -> FilePath-gitAnnexExportDbDir u r = gitAnnexExportDir r </> fromUUID u </> "exportdb"+gitAnnexExportDbDir :: UUID -> Git.Repo -> RawFilePath+gitAnnexExportDbDir u r = gitAnnexExportDir r P.</> fromUUID u P.</> "exportdb"  {- Lock file for export state for a special remote. -}-gitAnnexExportLock :: UUID -> Git.Repo -> FilePath-gitAnnexExportLock u r = gitAnnexExportDbDir u r ++ ".lck"+gitAnnexExportLock :: UUID -> Git.Repo -> RawFilePath+gitAnnexExportLock u r = gitAnnexExportDbDir u r <> ".lck"  {- Lock file for updating the export state for a special remote. -}-gitAnnexExportUpdateLock :: UUID -> Git.Repo -> FilePath-gitAnnexExportUpdateLock u r = gitAnnexExportDbDir u r ++ ".upl"+gitAnnexExportUpdateLock :: UUID -> Git.Repo -> RawFilePath+gitAnnexExportUpdateLock u r = gitAnnexExportDbDir u r <> ".upl"  {- Log file used to keep track of files that were in the tree exported to a  - remote, but were excluded by its preferred content settings. -}-gitAnnexExportExcludeLog :: UUID -> Git.Repo -> FilePath-gitAnnexExportExcludeLog u r = fromRawFilePath $-	gitAnnexDir r P.</> "export.ex" P.</> fromUUID u+gitAnnexExportExcludeLog :: UUID -> Git.Repo -> RawFilePath+gitAnnexExportExcludeLog u r = gitAnnexDir r P.</> "export.ex" P.</> fromUUID u  {- Directory containing database used to record remote content ids.  -  - (This used to be "cid", but a problem with the database caused it to  - need to be rebuilt with a new name.)  -}-gitAnnexContentIdentifierDbDir :: Git.Repo -> FilePath-gitAnnexContentIdentifierDbDir r = fromRawFilePath $ gitAnnexDir r P.</> "cidsdb"+gitAnnexContentIdentifierDbDir :: Git.Repo -> RawFilePath+gitAnnexContentIdentifierDbDir r = gitAnnexDir r P.</> "cidsdb"  {- Lock file for writing to the content id database. -}-gitAnnexContentIdentifierLock :: Git.Repo -> FilePath-gitAnnexContentIdentifierLock r = gitAnnexContentIdentifierDbDir r ++ ".lck"+gitAnnexContentIdentifierLock :: Git.Repo -> RawFilePath+gitAnnexContentIdentifierLock r = gitAnnexContentIdentifierDbDir r <> ".lck"  {- .git/annex/schedulestate is used to store information about when  - scheduled jobs were last run. -}-gitAnnexScheduleState :: Git.Repo -> FilePath-gitAnnexScheduleState r = fromRawFilePath $ gitAnnexDir r P.</> "schedulestate"+gitAnnexScheduleState :: Git.Repo -> RawFilePath+gitAnnexScheduleState r = gitAnnexDir r P.</> "schedulestate"  {- .git/annex/creds/ is used to store credentials to access some special  - remotes. -}-gitAnnexCredsDir :: Git.Repo -> FilePath-gitAnnexCredsDir r = fromRawFilePath $-	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "creds"+gitAnnexCredsDir :: Git.Repo -> RawFilePath+gitAnnexCredsDir r = P.addTrailingPathSeparator $ gitAnnexDir r P.</> "creds"  {- .git/annex/certificate.pem and .git/annex/key.pem are used by the webapp  - when HTTPS is enabled -}@@ -441,81 +407,78 @@ gitAnnexWebPrivKey r = fromRawFilePath $ gitAnnexDir r P.</> "privkey.pem"  {- .git/annex/feeds/ is used to record per-key (url) state by importfeeds -}-gitAnnexFeedStateDir :: Git.Repo -> FilePath-gitAnnexFeedStateDir r = fromRawFilePath $-	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "feedstate"+gitAnnexFeedStateDir :: Git.Repo -> RawFilePath+gitAnnexFeedStateDir r = P.addTrailingPathSeparator $+	gitAnnexDir r P.</> "feedstate" -gitAnnexFeedState :: Key -> Git.Repo -> FilePath-gitAnnexFeedState k r = gitAnnexFeedStateDir r </> fromRawFilePath (keyFile k)+gitAnnexFeedState :: Key -> Git.Repo -> RawFilePath+gitAnnexFeedState k r = gitAnnexFeedStateDir r P.</> keyFile k -{- .git/annex/merge/ is used as a empty work tree for direct mode merges and- - merges in adjusted branches. -}+{- .git/annex/merge/ is used as a empty work tree for merges in + - adjusted branches. -} gitAnnexMergeDir :: Git.Repo -> FilePath gitAnnexMergeDir r = fromRawFilePath $ 	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "merge"  {- .git/annex/transfer/ is used to record keys currently  - being transferred, and other transfer bookkeeping info. -}-gitAnnexTransferDir :: Git.Repo -> FilePath-gitAnnexTransferDir r = fromRawFilePath $+gitAnnexTransferDir :: Git.Repo -> RawFilePath+gitAnnexTransferDir r = 	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "transfer"  {- .git/annex/journal/ is used to journal changes made to the git-annex  - branch -}-gitAnnexJournalDir :: Git.Repo -> FilePath-gitAnnexJournalDir r = fromRawFilePath $+gitAnnexJournalDir :: Git.Repo -> RawFilePath+gitAnnexJournalDir r =  	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "journal"  gitAnnexJournalDir' :: Git.Repo -> RawFilePath-gitAnnexJournalDir' r = P.addTrailingPathSeparator $ gitAnnexDir r P.</> "journal"+gitAnnexJournalDir' r =+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "journal"  {- Lock file for the journal. -}-gitAnnexJournalLock :: Git.Repo -> FilePath-gitAnnexJournalLock r = fromRawFilePath $ gitAnnexDir r P.</> "journal.lck"+gitAnnexJournalLock :: Git.Repo -> RawFilePath+gitAnnexJournalLock r = gitAnnexDir r P.</> "journal.lck"  {- Lock file for flushing a git queue that writes to the git index or  - other git state that should only have one writer at a time. -}-gitAnnexGitQueueLock :: Git.Repo -> FilePath-gitAnnexGitQueueLock r = fromRawFilePath $ gitAnnexDir r P.</> "gitqueue.lck"--{- Lock file for direct mode merge. -}-gitAnnexMergeLock :: Git.Repo -> FilePath-gitAnnexMergeLock r = fromRawFilePath $ gitAnnexDir r P.</> "merge.lck"+gitAnnexGitQueueLock :: Git.Repo -> RawFilePath+gitAnnexGitQueueLock r = gitAnnexDir r P.</> "gitqueue.lck"  {- .git/annex/index is used to stage changes to the git-annex branch -}-gitAnnexIndex :: Git.Repo -> FilePath-gitAnnexIndex r = fromRawFilePath $ gitAnnexDir r P.</> "index"+gitAnnexIndex :: Git.Repo -> RawFilePath+gitAnnexIndex r = gitAnnexDir r P.</> "index"  {- Holds the ref of the git-annex branch that the index was last updated to.  -  - The .lck in the name is a historical accident; this is not used as a  - lock. -}-gitAnnexIndexStatus :: Git.Repo -> FilePath-gitAnnexIndexStatus r = fromRawFilePath $ gitAnnexDir r P.</> "index.lck"+gitAnnexIndexStatus :: Git.Repo -> RawFilePath+gitAnnexIndexStatus r = gitAnnexDir r P.</> "index.lck"  {- The index file used to generate a filtered branch view._-}-gitAnnexViewIndex :: Git.Repo -> FilePath-gitAnnexViewIndex r = fromRawFilePath $ gitAnnexDir r P.</> "viewindex"+gitAnnexViewIndex :: Git.Repo -> RawFilePath+gitAnnexViewIndex r = gitAnnexDir r P.</> "viewindex"  {- File containing a log of recently accessed views. -}-gitAnnexViewLog :: Git.Repo -> FilePath-gitAnnexViewLog r = fromRawFilePath $ gitAnnexDir r P.</> "viewlog"+gitAnnexViewLog :: Git.Repo -> RawFilePath+gitAnnexViewLog r = gitAnnexDir r P.</> "viewlog"  {- List of refs that have already been merged into the git-annex branch. -}-gitAnnexMergedRefs :: Git.Repo -> FilePath-gitAnnexMergedRefs r = fromRawFilePath $ gitAnnexDir r P.</> "mergedrefs"+gitAnnexMergedRefs :: Git.Repo -> RawFilePath+gitAnnexMergedRefs r = gitAnnexDir r P.</> "mergedrefs"  {- List of refs that should not be merged into the git-annex branch. -}-gitAnnexIgnoredRefs :: Git.Repo -> FilePath-gitAnnexIgnoredRefs r = fromRawFilePath $ gitAnnexDir r P.</> "ignoredrefs"+gitAnnexIgnoredRefs :: Git.Repo -> RawFilePath+gitAnnexIgnoredRefs r = gitAnnexDir r P.</> "ignoredrefs"  {- Pid file for daemon mode. -}-gitAnnexPidFile :: Git.Repo -> FilePath-gitAnnexPidFile r = fromRawFilePath $ gitAnnexDir r P.</> "daemon.pid"+gitAnnexPidFile :: Git.Repo -> RawFilePath+gitAnnexPidFile r = gitAnnexDir r P.</> "daemon.pid"  {- Pid lock file for pidlock mode -}-gitAnnexPidLockFile :: Git.Repo -> FilePath-gitAnnexPidLockFile r = fromRawFilePath $ gitAnnexDir r P.</> "pidlock"+gitAnnexPidLockFile :: Git.Repo -> RawFilePath+gitAnnexPidLockFile r = gitAnnexDir r P.</> "pidlock"  {- Status file for daemon mode. -} gitAnnexDaemonStatusFile :: Git.Repo -> FilePath@@ -523,8 +486,8 @@ 	gitAnnexDir r P.</> "daemon.status"  {- Log file for daemon mode. -}-gitAnnexDaemonLogFile :: Git.Repo -> FilePath-gitAnnexDaemonLogFile r = fromRawFilePath $ gitAnnexDir r P.</> "daemon.log"+gitAnnexDaemonLogFile :: Git.Repo -> RawFilePath+gitAnnexDaemonLogFile r = gitAnnexDir r P.</> "daemon.log"  {- Log file for fuzz test. -} gitAnnexFuzzTestLogFile :: Git.Repo -> FilePath@@ -532,25 +495,24 @@ 	gitAnnexDir r P.</> "fuzztest.log"  {- Html shim file used to launch the webapp. -}-gitAnnexHtmlShim :: Git.Repo -> FilePath-gitAnnexHtmlShim r = fromRawFilePath $ gitAnnexDir r P.</> "webapp.html"+gitAnnexHtmlShim :: Git.Repo -> RawFilePath+gitAnnexHtmlShim r = gitAnnexDir r P.</> "webapp.html"  {- File containing the url to the webapp. -}-gitAnnexUrlFile :: Git.Repo -> FilePath-gitAnnexUrlFile r = fromRawFilePath $ gitAnnexDir r P.</> "url"+gitAnnexUrlFile :: Git.Repo -> RawFilePath+gitAnnexUrlFile r = gitAnnexDir r P.</> "url"  {- Temporary file used to edit configuriation from the git-annex branch. -}-gitAnnexTmpCfgFile :: Git.Repo -> FilePath-gitAnnexTmpCfgFile r = fromRawFilePath $ gitAnnexDir r P.</> "config.tmp"+gitAnnexTmpCfgFile :: Git.Repo -> RawFilePath+gitAnnexTmpCfgFile r = gitAnnexDir r P.</> "config.tmp"  {- .git/annex/ssh/ is used for ssh connection caching -}-gitAnnexSshDir :: Git.Repo -> FilePath-gitAnnexSshDir r = fromRawFilePath $-	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "ssh"+gitAnnexSshDir :: Git.Repo -> RawFilePath+gitAnnexSshDir r = P.addTrailingPathSeparator $ gitAnnexDir r P.</> "ssh"  {- .git/annex/remotes/ is used for remote-specific state. -}-gitAnnexRemotesDir :: Git.Repo -> FilePath-gitAnnexRemotesDir r = fromRawFilePath $+gitAnnexRemotesDir :: Git.Repo -> RawFilePath+gitAnnexRemotesDir r = 	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "remotes"  {- This is the base directory name used by the assistant when making
Annex/LockFile.hs view
@@ -26,10 +26,11 @@ import Annex.LockPool  import qualified Data.Map as M+import qualified System.FilePath.ByteString as P  {- Create a specified lock file, and takes a shared lock, which is retained  - in the cache. -}-lockFileCached :: FilePath -> Annex ()+lockFileCached :: RawFilePath -> Annex () lockFileCached file = go =<< fromLockCache file   where 	go (Just _) = noop -- already locked@@ -42,7 +43,7 @@ #endif 		changeLockCache $ M.insert file lockhandle -unlockFile :: FilePath -> Annex ()+unlockFile :: RawFilePath -> Annex () unlockFile file = maybe noop go =<< fromLockCache file   where 	go lockhandle = do@@ -52,7 +53,7 @@ getLockCache :: Annex LockCache getLockCache = getState lockcache -fromLockCache :: FilePath -> Annex (Maybe LockHandle)+fromLockCache :: RawFilePath -> Annex (Maybe LockHandle) fromLockCache file = M.lookup file <$> getLockCache  changeLockCache :: (LockCache -> LockCache) -> Annex ()@@ -62,10 +63,10 @@  {- Runs an action with a shared lock held. If an exclusive lock is held,  - blocks until it becomes free. -}-withSharedLock :: (Git.Repo -> FilePath) -> Annex a -> Annex a+withSharedLock :: (Git.Repo -> RawFilePath) -> Annex a -> Annex a withSharedLock getlockfile a = debugLocks $ do 	lockfile <- fromRepo getlockfile-	createAnnexDirectory $ takeDirectory lockfile+	createAnnexDirectory $ P.takeDirectory lockfile 	mode <- annexFileMode 	bracket (lock mode lockfile) (liftIO . dropLock) (const a)   where@@ -77,17 +78,17 @@  {- Runs an action with an exclusive lock held. If the lock is already  - held, blocks until it becomes free. -}-withExclusiveLock :: (Git.Repo -> FilePath) -> Annex a -> Annex a+withExclusiveLock :: (Git.Repo -> RawFilePath) -> Annex a -> Annex a withExclusiveLock getlockfile a = bracket 	(takeExclusiveLock getlockfile) 	(liftIO . dropLock) 	(const a)  {- Takes an exclusive lock, blocking until it's free. -}-takeExclusiveLock :: (Git.Repo -> FilePath) -> Annex LockHandle+takeExclusiveLock :: (Git.Repo -> RawFilePath) -> Annex LockHandle takeExclusiveLock getlockfile = debugLocks $ do 	lockfile <- fromRepo getlockfile-	createAnnexDirectory $ takeDirectory lockfile+	createAnnexDirectory $ P.takeDirectory lockfile 	mode <- annexFileMode 	lock mode lockfile   where@@ -99,10 +100,10 @@  {- Tries to take an exclusive lock and run an action. If the lock is  - already held, returns Nothing. -}-tryExclusiveLock :: (Git.Repo -> FilePath) -> Annex a -> Annex (Maybe a)+tryExclusiveLock :: (Git.Repo -> RawFilePath) -> Annex a -> Annex (Maybe a) tryExclusiveLock getlockfile a = debugLocks $ do 	lockfile <- fromRepo getlockfile-	createAnnexDirectory $ takeDirectory lockfile+	createAnnexDirectory $ P.takeDirectory lockfile 	mode <- annexFileMode 	bracket (lock mode lockfile) (liftIO . unlock) go   where
Annex/NumCopies.hs view
@@ -63,7 +63,7 @@  {- Numcopies value for a file, from any configuration source, including the  - deprecated git config. -}-getFileNumCopies :: FilePath -> Annex NumCopies+getFileNumCopies :: RawFilePath -> Annex NumCopies getFileNumCopies f = fromSources 	[ getForcedNumCopies 	, getFileNumCopies' f@@ -72,17 +72,17 @@  getAssociatedFileNumCopies :: AssociatedFile -> Annex NumCopies getAssociatedFileNumCopies (AssociatedFile afile) =-	maybe getNumCopies getFileNumCopies (fromRawFilePath <$> afile)+	maybe getNumCopies getFileNumCopies afile  {- This is the globally visible numcopies value for a file. So it does  - not include local configuration in the git config or command line  - options. -}-getGlobalFileNumCopies :: FilePath  -> Annex NumCopies+getGlobalFileNumCopies :: RawFilePath  -> Annex NumCopies getGlobalFileNumCopies f = fromSources 	[ getFileNumCopies' f 	] -getFileNumCopies' :: FilePath  -> Annex (Maybe NumCopies)+getFileNumCopies' :: RawFilePath  -> Annex (Maybe NumCopies) getFileNumCopies' file = maybe getGlobalNumCopies (return . Just) =<< getattr   where 	getattr = (NumCopies <$$> readish)@@ -95,12 +95,12 @@  - This is good enough for everything except dropping the file, which  - requires active verification of the copies.  -}-numCopiesCheck :: FilePath -> Key -> (Int -> Int -> v) -> Annex v+numCopiesCheck :: RawFilePath -> Key -> (Int -> Int -> v) -> Annex v numCopiesCheck file key vs = do 	have <- trustExclude UnTrusted =<< Remote.keyLocations key 	numCopiesCheck' file vs have -numCopiesCheck' :: FilePath -> (Int -> Int -> v) -> [UUID] -> Annex v+numCopiesCheck' :: RawFilePath -> (Int -> Int -> v) -> [UUID] -> Annex v numCopiesCheck' file vs have = do 	NumCopies needed <- getFileNumCopies file 	return $ length have `vs` needed
Annex/Perms.hs view
@@ -31,24 +31,26 @@ import Git.ConfigTypes import qualified Annex import Config+import Utility.Directory.Create+import qualified Utility.RawFilePath as R  withShared :: (SharedRepository -> Annex a) -> Annex a withShared a = a =<< coreSharedRepository <$> Annex.getGitConfig -setAnnexFilePerm :: FilePath -> Annex ()+setAnnexFilePerm :: RawFilePath -> Annex () setAnnexFilePerm = setAnnexPerm False -setAnnexDirPerm :: FilePath -> Annex ()+setAnnexDirPerm :: RawFilePath -> Annex () setAnnexDirPerm = setAnnexPerm True  {- Sets appropriate file mode for a file or directory in the annex,  - other than the content files and content directory. Normally,  - don't change the mode, but with core.sharedRepository set,  - allow the group to write, etc. -}-setAnnexPerm :: Bool -> FilePath -> Annex ()+setAnnexPerm :: Bool -> RawFilePath -> Annex () setAnnexPerm = setAnnexPerm' Nothing -setAnnexPerm' :: Maybe ([FileMode] -> FileMode -> FileMode) -> Bool -> FilePath -> Annex ()+setAnnexPerm' :: Maybe ([FileMode] -> FileMode -> FileMode) -> Bool -> RawFilePath -> Annex () setAnnexPerm' modef isdir file = unlessM crippledFileSystem $ 	withShared $ liftIO . go   where@@ -65,7 +67,7 @@ 			modifyFileMode file $ f [] 	modef' = fromMaybe addModes modef -resetAnnexFilePerm :: FilePath -> Annex ()+resetAnnexFilePerm :: RawFilePath -> Annex () resetAnnexFilePerm = resetAnnexPerm False  {- Like setAnnexPerm, but ignores the current mode of the file entirely,@@ -76,7 +78,7 @@  - which is going to be moved to a non-temporary location and needs  - usual modes.  -}-resetAnnexPerm :: Bool -> FilePath -> Annex ()+resetAnnexPerm :: Bool -> RawFilePath -> Annex () resetAnnexPerm isdir file = unlessM crippledFileSystem $ do 	defmode <- liftIO defaultFileMode 	let modef moremodes _oldmode = addModes moremodes defmode@@ -97,13 +99,13 @@ {- Creates a directory inside the gitAnnexDir, creating any parent  - directories up to and including the gitAnnexDir.  - Makes directories with appropriate permissions. -}-createAnnexDirectory :: FilePath -> Annex ()+createAnnexDirectory :: RawFilePath -> Annex () createAnnexDirectory dir = do-	top <- parentDir . fromRawFilePath <$> fromRepo gitAnnexDir+	top <- parentDir <$> fromRepo gitAnnexDir 	createDirectoryUnder' top dir createdir   where 	createdir p = do-		liftIO $ createDirectory p+		liftIO $ R.createDirectory p 		setAnnexDirPerm p  {- Create a directory in the git work tree, creating any parent@@ -111,10 +113,10 @@  -  - Uses default permissions.  -}-createWorkTreeDirectory :: FilePath -> Annex ()+createWorkTreeDirectory :: RawFilePath -> Annex () createWorkTreeDirectory dir = do 	fromRepo repoWorkTree >>= liftIO . \case-		Just wt -> createDirectoryUnder (fromRawFilePath wt) dir+		Just wt -> createDirectoryUnder wt dir 		-- Should never happen, but let whatever tries to write 		-- to the directory be what throws an exception, as that 		-- will be clearer than an exception from here.@@ -129,7 +131,7 @@  - shared repository, the current user may not be able to change a file  - owned by another user, so failure to set this mode is ignored.  -}-freezeContent :: FilePath -> Annex ()+freezeContent :: RawFilePath -> Annex () freezeContent file = unlessM crippledFileSystem $ 	withShared go   where@@ -141,7 +143,7 @@ 		removeModes writeModes . 		addModes [ownerReadMode] -isContentWritePermOk :: FilePath -> Annex Bool+isContentWritePermOk :: RawFilePath -> Annex Bool isContentWritePermOk file = ifM crippledFileSystem 	( return True 	, withShared go@@ -151,12 +153,12 @@ 	go AllShared = want writeModes 	go _ = return True 	want wantmode =-		liftIO (catchMaybeIO $ fileMode <$> getFileStatus file) >>= return . \case+		liftIO (catchMaybeIO $ fileMode <$> R.getFileStatus file) >>= return . \case 			Nothing -> True 			Just havemode -> havemode == combineModes (havemode:wantmode)  {- Adjusts read mode of annexed file per core.sharedRepository setting. -}-chmodContent :: FilePath -> Annex ()+chmodContent :: RawFilePath -> Annex () chmodContent file = unlessM crippledFileSystem $ 	withShared go   where@@ -169,7 +171,7 @@  {- Allows writing to an annexed file that freezeContent was called on  - before. -}-thawContent :: FilePath -> Annex ()+thawContent :: RawFilePath -> Annex () thawContent file = thawPerms $ withShared go   where 	go GroupShared = liftIO $ void $ tryIO $ groupWriteRead file@@ -190,7 +192,7 @@  - is set, this is not done, since the group must be allowed to delete the  - file.  -}-freezeContentDir :: FilePath -> Annex ()+freezeContentDir :: RawFilePath -> Annex () freezeContentDir file = unlessM crippledFileSystem $ 	withShared go   where@@ -199,14 +201,15 @@ 	go AllShared = liftIO $ void $ tryIO $ groupWriteRead dir 	go _ = liftIO $ preventWrite dir -thawContentDir :: FilePath -> Annex ()-thawContentDir file = thawPerms $ liftIO $ allowWrite $ parentDir file+thawContentDir :: RawFilePath -> Annex ()+thawContentDir file = +	thawPerms $ liftIO $ allowWrite $ parentDir file  {- Makes the directory tree to store an annexed file's content,  - with appropriate permissions on each level. -}-createContentDir :: FilePath -> Annex ()+createContentDir :: RawFilePath -> Annex () createContentDir dest = do-	unlessM (liftIO $ doesDirectoryExist dir) $+	unlessM (liftIO $ R.doesPathExist dir) $ 		createAnnexDirectory dir  	-- might have already existed with restricted perms 	unlessM crippledFileSystem $@@ -217,7 +220,7 @@ {- Creates the content directory for a file if it doesn't already exist,  - or thaws it if it does, then runs an action to modify the file, and  - finally, freezes the content directory. -}-modifyContent :: FilePath -> Annex a -> Annex a+modifyContent :: RawFilePath -> Annex a -> Annex a modifyContent f a = do 	createContentDir f -- also thaws it 	v <- tryNonAsync a
Annex/Queue.hs view
@@ -31,7 +31,7 @@ 	store =<< flushWhenFull =<< 		(Git.Queue.addCommand command params files q =<< gitRepo) -addInternalAction :: Git.Queue.InternalActionRunner Annex -> [(FilePath, IO Bool)] -> Annex ()+addInternalAction :: Git.Queue.InternalActionRunner Annex -> [(RawFilePath, IO Bool)] -> Annex () addInternalAction runner files = do 	q <- get 	store =<< flushWhenFull =<<
Annex/ReplaceFile.hs view
@@ -19,6 +19,7 @@ import Annex.Perms import Git import Utility.Tmp.Dir+import Utility.Directory.Create #ifndef mingw32_HOST_OS import Utility.Path.Max #endif@@ -30,7 +31,7 @@ {- replaceFile on a file located inside the .git directory. -} replaceGitDirFile :: FilePath -> (FilePath -> Annex a) -> Annex a replaceGitDirFile = replaceFile $ \dir -> do-	top <- fromRawFilePath <$> fromRepo localGitDir+	top <- fromRepo localGitDir 	liftIO $ createDirectoryUnder top dir  {- replaceFile on a worktree file. -}@@ -52,29 +53,30 @@  - The createdirectory action is only run when moving the file into place  - fails, and can create any parent directory structure needed.  -}-replaceFile :: (FilePath -> Annex ()) -> FilePath -> (FilePath -> Annex a) -> Annex a+replaceFile :: (RawFilePath -> Annex ()) -> FilePath -> (FilePath -> Annex a) -> Annex a replaceFile createdirectory file action = withOtherTmp $ \othertmpdir -> do+	let othertmpdir' = fromRawFilePath othertmpdir #ifndef mingw32_HOST_OS 	-- Use part of the filename as the template for the temp 	-- directory. This does not need to be unique, but it 	-- makes it more clear what this temp directory is for.-	filemax <- liftIO $ fileNameLengthLimit othertmpdir+	filemax <- liftIO $ fileNameLengthLimit othertmpdir' 	let basetmp = take (filemax `div` 2) (takeFileName file) #else 	-- Windows has limits on the whole path length, so keep 	-- it short. 	let basetmp = "t" #endif-	withTmpDirIn othertmpdir basetmp $ \tmpdir -> do+	withTmpDirIn othertmpdir' basetmp $ \tmpdir -> do 		let tmpfile = tmpdir </> basetmp 		r <- action tmpfile 		replaceFileFrom tmpfile file createdirectory 		return r -replaceFileFrom :: FilePath -> FilePath -> (FilePath -> Annex ()) -> Annex ()+replaceFileFrom :: FilePath -> FilePath -> (RawFilePath -> Annex ()) -> Annex () replaceFileFrom src dest createdirectory = go `catchIO` fallback   where 	go = liftIO $ moveFile src dest 	fallback _ = do-		createdirectory (parentDir dest)+		createdirectory (parentDir (toRawFilePath dest)) 		go
Annex/Ssh.hs view
@@ -38,6 +38,7 @@ import Types.Concurrency import Git.Env import Git.Ssh+import qualified Utility.RawFilePath as R import Annex.Perms #ifndef mingw32_HOST_OS import Annex.LockPool@@ -45,6 +46,7 @@  import Control.Concurrent.STM import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P  {- Some ssh commands are fed stdin on a pipe and so should be allowed to  - consume it. But ssh commands that are not piped stdin should generally@@ -102,9 +104,11 @@ sshCachingInfo (host, port) = go =<< sshCacheDir'   where 	go (Right dir) =-		liftIO (bestSocketPath $ dir </> hostport2socket host port) >>= return . \case+		liftIO (bestSocketPath $ dir P.</> hostport2socket host port) >>= return . \case 			Nothing -> (Nothing, [])-			Just socketfile -> (Just socketfile, sshConnectionCachingParams socketfile)+			Just socketfile -> +				let socketfile' = fromRawFilePath socketfile+				in (Just socketfile', sshConnectionCachingParams socketfile') 	-- No connection caching with concurrency is not a good 	-- combination, so warn the user. 	go (Left whynocaching) = do@@ -130,20 +134,20 @@  - file.  -  - If no path can be constructed that is a valid socket, returns Nothing. -}-bestSocketPath :: FilePath -> IO (Maybe FilePath)+bestSocketPath :: RawFilePath -> IO (Maybe RawFilePath) bestSocketPath abssocketfile = do 	relsocketfile <- liftIO $ relPathCwdToFile abssocketfile-	let socketfile = if length abssocketfile <= length relsocketfile+	let socketfile = if S.length abssocketfile <= S.length relsocketfile 		then abssocketfile 		else relsocketfile-	return $ if valid_unix_socket_path (socketfile ++ sshgarbage)+	return $ if valid_unix_socket_path socketfile sshgarbagelen 			then Just socketfile 			else Nothing   where 	-- ssh appends a 16 char extension to the socket when setting it 	-- up, which needs to be taken into account when checking 	-- that a valid socket was constructed.-	sshgarbage = replicate (1+16) 'X'+	sshgarbagelen = 1+16  sshConnectionCachingParams :: FilePath -> [CommandParam] sshConnectionCachingParams socketfile = @@ -160,10 +164,10 @@  -   - The directory will be created if it does not exist.  -}-sshCacheDir :: Annex (Maybe FilePath)+sshCacheDir :: Annex (Maybe RawFilePath) sshCacheDir = eitherToMaybe <$> sshCacheDir' -sshCacheDir' :: Annex (Either String FilePath)+sshCacheDir' :: Annex (Either String RawFilePath) sshCacheDir' =  	ifM (fromMaybe BuildInfo.sshconnectioncaching . annexSshCaching <$> Annex.getGitConfig) 		( ifM crippledFileSystem@@ -186,7 +190,7 @@ 	usetmpdir tmpdir = do 		let socktmp = tmpdir </> "ssh" 		createDirectoryIfMissing True socktmp-		return socktmp+		return (toRawFilePath socktmp) 	 	crippledfswarning = unwords 		[ "This repository is on a crippled filesystem, so unix named"@@ -285,9 +289,9 @@ enumSocketFiles = liftIO . go =<< sshCacheDir   where 	go Nothing = return []-	go (Just dir) = filterM (doesFileExist . socket2lock)+	go (Just dir) = filterM (R.doesPathExist . socket2lock) 		=<< filter (not . isLock)-		<$> catchDefaultIO [] (dirContents dir)+		<$> catchDefaultIO [] (dirContents (fromRawFilePath dir))  {- Stop any unused ssh connection caching processes. -} sshCleanup :: Annex ()@@ -333,25 +337,25 @@ 		} 	void $ liftIO $ catchMaybeIO $ withCreateProcess p $ \_ _ _ pid -> 		forceSuccessProcess p pid-	liftIO $ nukeFile socketfile+	liftIO $ removeWhenExistsWith removeLink socketfile  {- This needs to be as short as possible, due to limitations on the length  - of the path to a socket file. At the same time, it needs to be unique  - for each host.  -}-hostport2socket :: SshHost -> Maybe Integer -> FilePath+hostport2socket :: SshHost -> Maybe Integer -> RawFilePath hostport2socket host Nothing = hostport2socket' $ fromSshHost host hostport2socket host (Just port) = hostport2socket' $ 	fromSshHost host ++ "!" ++ show port-hostport2socket' :: String -> FilePath+hostport2socket' :: String -> RawFilePath hostport2socket' s-	| length s > lengthofmd5s = show $ md5 $ encodeBL s-	| otherwise = s+	| length s > lengthofmd5s = toRawFilePath $ show $ md5 $ encodeBL s+	| otherwise = toRawFilePath s   where 	lengthofmd5s = 32 -socket2lock :: FilePath -> FilePath-socket2lock socket = socket ++ lockExt+socket2lock :: FilePath -> RawFilePath+socket2lock socket = toRawFilePath (socket ++ lockExt)  isLock :: FilePath -> Bool isLock f = lockExt `isSuffixOf` f@@ -369,8 +373,8 @@  {- Note that this looks at the true length of the path in bytes, as it will  - appear on disk. -}-valid_unix_socket_path :: FilePath -> Bool-valid_unix_socket_path f = S.length (encodeBS f) < sizeof_sockaddr_un_sun_path+valid_unix_socket_path :: RawFilePath -> Int -> Bool+valid_unix_socket_path f n = S.length f + n < sizeof_sockaddr_un_sun_path  {- Parses the SSH port, and returns the other OpenSSH options. If  - several ports are found, the last one takes precedence. -}
Annex/Tmp.hs view
@@ -21,7 +21,7 @@ -- directory that is passed to it. However, once the action is done, -- any files left in that directory may be cleaned up by another process at -- any time.-withOtherTmp :: (FilePath -> Annex a) -> Annex a+withOtherTmp :: (RawFilePath -> Annex a) -> Annex a withOtherTmp a = do 	Annex.addCleanup OtherTmpCleanup cleanupOtherTmp 	tmpdir <- fromRepo gitAnnexTmpOtherDir@@ -38,14 +38,14 @@ -- Unlike withOtherTmp, this does not rely on locking working. -- Its main use is in situations where the state of lockfile is not -- determined yet, eg during initialization.-withEventuallyCleanedOtherTmp :: (FilePath -> Annex a) -> Annex a+withEventuallyCleanedOtherTmp :: (RawFilePath -> Annex a) -> Annex a withEventuallyCleanedOtherTmp = bracket setup cleanup   where 	setup = do 		tmpdir <- fromRepo gitAnnexTmpOtherDirOld 		void $ createAnnexDirectory tmpdir 		return tmpdir-	cleanup = liftIO . void . tryIO . removeDirectory +	cleanup = liftIO . void . tryIO . removeDirectory . fromRawFilePath  -- | Cleans up any tmp files that were left by a previous -- git-annex process that got interrupted or failed to clean up after@@ -56,9 +56,9 @@ cleanupOtherTmp = do 	tmplck <- fromRepo gitAnnexTmpOtherLock 	void $ tryIO $ tryExclusiveLock (const tmplck) $ do-		tmpdir <- fromRepo gitAnnexTmpOtherDir+		tmpdir <- fromRawFilePath <$> fromRepo gitAnnexTmpOtherDir 		void $ liftIO $ tryIO $ removeDirectoryRecursive tmpdir-		oldtmp <- fromRepo gitAnnexTmpOtherDirOld+		oldtmp <- fromRawFilePath <$> fromRepo gitAnnexTmpOtherDirOld 		liftIO $ mapM_ cleanold =<< dirContentsRecursive oldtmp 		liftIO $ void $ tryIO $ removeDirectory oldtmp -- when empty   where@@ -67,5 +67,5 @@ 		let oldenough = now - (60 * 60 * 24 * 7) 		catchMaybeIO (modificationTime <$> getSymbolicLinkStatus f) >>= \case 			Just mtime | realToFrac mtime <= oldenough -> -				void $ tryIO $ nukeFile f+				void $ tryIO $ removeWhenExistsWith removeLink f 			_ -> return ()
Annex/Transfer.hs view
@@ -35,9 +35,11 @@ import Types.WorkerPool import Annex.WorkerPool import Backend (isCryptographicallySecure)+import qualified Utility.RawFilePath as R  import Control.Concurrent import qualified Data.Map.Strict as M+import qualified System.FilePath.ByteString as P import Data.Ord  upload :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v@@ -96,11 +98,11 @@ 				else recordFailedTransfer t info 			return v   where-	prep :: FilePath -> Annex () -> FileMode -> Annex (Maybe LockHandle, Bool)+	prep :: RawFilePath -> Annex () -> FileMode -> Annex (Maybe LockHandle, Bool) #ifndef mingw32_HOST_OS 	prep tfile createtfile mode = catchPermissionDenied (const prepfailed) $ do 		let lck = transferLockFile tfile-		createAnnexDirectory $ takeDirectory lck+		createAnnexDirectory $ P.takeDirectory lck 		tryLockExclusive (Just mode) lck >>= \case 			Nothing -> return (Nothing, True) 			Just lockhandle -> ifM (checkSaneLock lck lockhandle)@@ -114,7 +116,7 @@ #else 	prep tfile createtfile _mode = catchPermissionDenied (const prepfailed) $ do 		let lck = transferLockFile tfile-		createAnnexDirectory $ takeDirectory lck+		createAnnexDirectory $ P.takeDirectory lck 		catchMaybeIO (liftIO $ lockExclusive lck) >>= \case 			Nothing -> return (Nothing, False) 			Just Nothing -> return (Nothing, True)@@ -127,9 +129,9 @@ 	cleanup _ Nothing = noop 	cleanup tfile (Just lockhandle) = do 		let lck = transferLockFile tfile-		void $ tryIO $ removeFile tfile+		void $ tryIO $ R.removeLink tfile #ifndef mingw32_HOST_OS-		void $ tryIO $ removeFile lck+		void $ tryIO $ R.removeLink lck 		dropLock lockhandle #else 		{- Windows cannot delete the lockfile until the lock@@ -138,7 +140,7 @@ 		 - so ignore failure to remove. 		 -} 		dropLock lockhandle-		void $ tryIO $ removeFile lck+		void $ tryIO $ R.removeLink lck #endif  	retry numretries oldinfo metervar run =
Annex/View.hs view
@@ -33,11 +33,13 @@ import Utility.Glob import Types.Command import CmdLine.Action+import qualified Utility.RawFilePath as R  import qualified Data.Text as T import qualified Data.ByteString as B import qualified Data.Set as S import qualified Data.Map as M+import qualified System.FilePath.ByteString as P import "mtl" Control.Monad.Writer  {- Each visible ViewFilter in a view results in another level of@@ -292,12 +294,12 @@  - it to a file yields a set of ViewedFile which all contain the same  - MetaFields that were present in the input metadata  - (excluding fields that are not visible). -}-prop_view_roundtrips :: FilePath -> MetaData -> Bool -> Bool-prop_view_roundtrips f metadata visible = or-	[ null f-	, null (takeFileName f) && null (takeDirectory f)+prop_view_roundtrips :: AssociatedFile -> MetaData -> Bool -> Bool+prop_view_roundtrips (AssociatedFile Nothing) _ _ = True+prop_view_roundtrips (AssociatedFile (Just f)) metadata visible = or+	[ B.null (P.takeFileName f) && B.null (P.takeDirectory f) 	, viewTooLarge view-	, all hasfields (viewedFiles view viewedFileFromReference f metadata)+	, all hasfields (viewedFiles view viewedFileFromReference (fromRawFilePath f) metadata) 	]   where 	view = View (Git.Ref "foo") $@@ -353,7 +355,7 @@ applyView' mkviewedfile getfilemetadata view = do 	top <- fromRepo Git.repoPath 	(l, clean) <- inRepo $ Git.LsFiles.inRepoDetails [] [top]-	liftIO . nukeFile =<< fromRepo gitAnnexViewIndex+	liftIO . removeWhenExistsWith R.removeLink =<< fromRepo gitAnnexViewIndex 	viewg <- withViewIndex gitRepo 	withUpdateIndex viewg $ \uh -> do 		forM_ l $ \(f, sha, mode) -> do@@ -369,8 +371,7 @@ 		let f = fromRawFilePath $ getTopFilePath topf 		let metadata' = getfilemetadata f `unionMetaData` metadata 		forM_ (genviewedfiles f metadata') $ \fv -> do-			f' <- fromRawFilePath <$> -				fromRepo (fromTopFilePath $ asTopFilePath $ toRawFilePath fv)+			f' <- fromRepo (fromTopFilePath $ asTopFilePath $ toRawFilePath fv) 			stagesymlink uh f' =<< calcRepo (gitAnnexLink f' k) 	go uh topf sha (Just treeitemtype) Nothing 		| "." `B.isPrefixOf` getTopFilePath topf =
Annex/View/ViewedFile.hs view
@@ -17,7 +17,10 @@ ) where  import Annex.Common+import Utility.QuickCheck +import qualified Data.ByteString as S+ type FileName = String type ViewedFile = FileName @@ -34,14 +37,14 @@  -} viewedFileFromReference :: MkViewedFile viewedFileFromReference f = concat-	[ escape base+	[ escape (fromRawFilePath base) 	, if null dirs then "" else "_%" ++ intercalate "%" (map escape dirs) ++ "%"-	, escape $ concat extensions+	, escape $ fromRawFilePath $ S.concat extensions 	]   where 	(path, basefile) = splitFileName f 	dirs = filter (/= ".") $ map dropTrailingPathSeparator (splitPath path)-	(base, extensions) = splitShortExtensions basefile+	(base, extensions) = splitShortExtensions (toRawFilePath basefile)  	{- To avoid collisions with filenames or directories that contain 	 - '%', and to allow the original directories to be extracted@@ -76,11 +79,12 @@ 			[] -> sep l curr cs 		| otherwise = sep l (c:curr) cs -prop_viewedFile_roundtrips :: FilePath -> Bool-prop_viewedFile_roundtrips f+prop_viewedFile_roundtrips :: TestableFilePath -> Bool+prop_viewedFile_roundtrips tf 	-- Relative filenames wanted, not directories. 	| any (isPathSeparator) (end f ++ beginning f) = True 	| isAbsolute f = True 	| otherwise = dir == dirFromViewedFile (viewedFileFromReference f)   where+	f = fromTestableFilePath tf 	dir = joinPath $ beginning $ splitDirectories f
Annex/WorkTree.hs view
@@ -106,7 +106,7 @@ 						fileMode <$> R.getFileStatus f 					ic <- replaceWorkTreeFile (fromRawFilePath f) $ \tmp -> do 						let tmp' = toRawFilePath tmp-						linkFromAnnex k tmp destmode >>= \case+						linkFromAnnex k tmp' destmode >>= \case 							LinkAnnexOk ->  								withTSDelta (liftIO . genInodeCache tmp') 							LinkAnnexNoop -> return Nothing
Annex/YoutubeDl.hs view
@@ -123,7 +123,7 @@ 		Just have -> do 			inprogress <- sizeOfDownloadsInProgress (const True) 			partial <- liftIO $ sum -				<$> (mapM getFileSize =<< dirContents workdir)+				<$> (mapM (getFileSize . toRawFilePath) =<< dirContents workdir) 			reserve <- annexDiskReserve <$> Annex.getGitConfig 			let maxsize = have - reserve - inprogress + partial 			if maxsize > 0@@ -141,7 +141,7 @@ youtubeDlTo :: Key -> URLString -> FilePath -> MeterUpdate -> Annex Bool youtubeDlTo key url dest p = do 	res <- withTmpWorkDir key $ \workdir ->-		youtubeDl url workdir p >>= \case+		youtubeDl url (fromRawFilePath workdir) p >>= \case 			Right (Just mediafile) -> do 				liftIO $ renameFile mediafile dest 				return (Just True)
Assistant.hs view
@@ -62,7 +62,8 @@ import Network.Socket (HostName)  stopDaemon :: Annex ()-stopDaemon = liftIO . Utility.Daemon.stopDaemon =<< fromRepo gitAnnexPidFile+stopDaemon = liftIO . Utility.Daemon.stopDaemon . fromRawFilePath+	=<< fromRepo gitAnnexPidFile  {- Starts the daemon. If the daemon is run in the foreground, once it's  - running, can start the browser.@@ -75,24 +76,24 @@ 	enableInteractiveBranchAccess 	pidfile <- fromRepo gitAnnexPidFile 	logfile <- fromRepo gitAnnexDaemonLogFile-	liftIO $ debugM desc $ "logging to " ++ logfile+	liftIO $ debugM desc $ "logging to " ++ fromRawFilePath logfile 	createAnnexDirectory (parentDir pidfile) #ifndef mingw32_HOST_OS 	createAnnexDirectory (parentDir logfile)-	logfd <- liftIO $ handleToFd =<< openLog logfile+	logfd <- liftIO $ handleToFd =<< openLog (fromRawFilePath logfile) 	if foreground 		then do 			origout <- liftIO $ catchMaybeIO $  				fdToHandle =<< dup stdOutput 			origerr <- liftIO $ catchMaybeIO $  				fdToHandle =<< dup stdError-			let undaemonize = Utility.Daemon.foreground logfd (Just pidfile)+			let undaemonize = Utility.Daemon.foreground logfd (Just (fromRawFilePath pidfile)) 			start undaemonize $  				case startbrowser of 					Nothing -> Nothing 					Just a -> Just $ a origout origerr 		else-			start (Utility.Daemon.daemonize logfd (Just pidfile) False) Nothing+			start (Utility.Daemon.daemonize logfd (Just (fromRawFilePath pidfile)) False) Nothing #else 	-- Windows doesn't daemonize, but does redirect output to the 	-- log file. The only way to do so is to restart the program.@@ -128,7 +129,7 @@ 		checkCanWatch 		dstatus <- startDaemonStatus 		logfile <- fromRepo gitAnnexDaemonLogFile-		liftIO $ debugM desc $ "logging to " ++ logfile+		liftIO $ debugM desc $ "logging to " ++ fromRawFilePath logfile 		liftIO $ daemonize $ 			flip runAssistant (go webappwaiter)  				=<< newAssistantData st dstatus
Assistant/Install.hs view
@@ -51,7 +51,8 @@ 	go (Just base) = do 		let program = base </> "git-annex" 		programfile <- programFile-		createDirectoryIfMissing True (parentDir programfile)+		createDirectoryIfMissing True $+			fromRawFilePath (parentDir (toRawFilePath programfile)) 		writeFile programfile program  #ifdef darwin_HOST_OS@@ -100,9 +101,10 @@ installWrapper file content = do 	curr <- catchDefaultIO "" $ readFileStrict file 	when (curr /= content) $ do-		createDirectoryIfMissing True (parentDir file)+		createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath file))) 		viaTmp writeFile file content-		modifyFileMode file $ addModes [ownerExecuteMode]+		modifyFileMode (toRawFilePath file) $ +			addModes [ownerExecuteMode]  installFileManagerHooks :: FilePath -> IO () #ifdef linux_HOST_OS@@ -131,7 +133,7 @@ 	scriptname action = "git-annex " ++ action 	installscript f c = whenM (safetoinstallscript f) $ do 		writeFile f c-		modifyFileMode f $ addModes [ownerExecuteMode]+		modifyFileMode (toRawFilePath f) $ addModes [ownerExecuteMode] 	safetoinstallscript f = catchDefaultIO True $ 		elem autoaddedcomment . lines <$> readFileStrict f 	autoaddedcomment = "# " ++ autoaddedmsg ++ " (To disable, chmod 600 this file.)"
Assistant/Install/AutoStart.hs view
@@ -15,12 +15,13 @@ import Utility.OSX import Utility.Path import Utility.Directory+import Utility.FileSystemEncoding #endif  installAutoStart :: FilePath -> FilePath -> IO () installAutoStart command file = do #ifdef darwin_HOST_OS-	createDirectoryIfMissing True (parentDir file)+	createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath file))) 	writeFile file $ genOSXAutoStartFile osxAutoStartLabel command 		["assistant", "--autostart"] #else
Assistant/Install/Menu.hs view
@@ -10,10 +10,16 @@  module Assistant.Install.Menu where -import Common- import Utility.FreeDesktop+import Utility.FileSystemEncoding+import Utility.Path +import System.IO+import Utility.SystemDirectory+#ifndef darwin_HOST_OS+import System.FilePath+#endif+ installMenu :: FilePath -> FilePath -> FilePath -> FilePath -> IO () #ifdef darwin_HOST_OS installMenu _command _menufile _iconsrcdir _icondir = return ()@@ -39,7 +45,7 @@  installIcon :: FilePath -> FilePath -> IO () installIcon src dest = do-	createDirectoryIfMissing True (parentDir dest)+	createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath dest))) 	withBinaryFile src ReadMode $ \hin -> 		withBinaryFile dest WriteMode $ \hout -> 			hGetContents hin >>= hPutStr hout
Assistant/MakeRepo.hs view
@@ -46,7 +46,9 @@ {- Runs an action in the git repository in the specified directory. -} inDir :: FilePath -> Annex a -> IO a inDir dir a = do-	state <- Annex.new =<< Git.Config.read =<< Git.Construct.fromPath dir+	state <- Annex.new+		=<< Git.Config.read+		=<< Git.Construct.fromPath (toRawFilePath dir) 	Annex.eval state $ a `finally` stopCoProcesses  {- Creates a new repository, and returns its UUID. -}
Assistant/Pairing/MakeRemote.hs view
@@ -26,7 +26,7 @@ setupAuthorizedKeys msg repodir = case validateSshPubKey $ remoteSshPubKey $ pairMsgData msg of 	Left err -> error err 	Right pubkey -> do-		absdir <- absPath repodir+		absdir <- fromRawFilePath <$> absPath (toRawFilePath repodir) 		unlessM (liftIO $ addAuthorizedKeys True absdir pubkey) $ 			error "failed setting up ssh authorized keys" 
Assistant/Repair.hs view
@@ -91,10 +91,10 @@ 	remoterepair fsckresults = case Remote.repairRepo =<< mrmt of 		Nothing -> return False 		Just mkrepair -> do-			thisrepopath <- liftIO . absPath . fromRawFilePath+			thisrepopath <- liftIO . absPath 				=<< liftAnnex (fromRepo Git.repoPath) 			a <- liftAnnex $ mkrepair $-				repair fsckresults (Just thisrepopath)+				repair fsckresults (Just (fromRawFilePath thisrepopath)) 			liftIO $ catchBoolIO a  	repair fsckresults referencerepo = do@@ -140,7 +140,8 @@ repairStaleLocks :: [FilePath] -> Assistant () repairStaleLocks lockfiles = go =<< getsizes   where-	getsize lf = catchMaybeIO $ (\s -> (lf, s)) <$> getFileSize lf+	getsize lf = catchMaybeIO $ (\s -> (lf, s))+		<$> getFileSize (toRawFilePath lf) 	getsizes = liftIO $ catMaybes <$> mapM getsize lockfiles 	go [] = return () 	go l = ifM (liftIO $ null <$> Lsof.query ("--" : map fst l))@@ -148,7 +149,7 @@ 			waitforit "to check stale git lock file" 			l' <- getsizes 			if l' == l-				then liftIO $ mapM_ nukeFile (map fst l)+				then liftIO $ mapM_ (removeWhenExistsWith removeLink . fst) l 				else go l' 		, do 			waitforit "for git lock file writer"
Assistant/Restart.hs view
@@ -17,6 +17,7 @@ import Utility.NotificationBroadcaster import Utility.Url import Utility.PID+import qualified Utility.RawFilePath as R import qualified Git.Construct import qualified Git.Config import qualified Annex@@ -39,8 +40,8 @@ prepRestart :: Assistant () prepRestart = do 	liftIO . maybe noop (`throwTo` PauseWatcher) =<< namedThreadId watchThread-	liftIO . nukeFile =<< liftAnnex (fromRepo gitAnnexUrlFile)-	liftIO . nukeFile =<< liftAnnex (fromRepo gitAnnexPidFile)+	liftIO . removeWhenExistsWith R.removeLink =<< liftAnnex (fromRepo gitAnnexUrlFile)+	liftIO . removeWhenExistsWith R.removeLink =<< liftAnnex (fromRepo gitAnnexPidFile)  {- To finish a restart, send a global redirect to the new url  - to any web browsers that are displaying the webapp.@@ -75,8 +76,8 @@ 	geturl   where 	geturl = do-		r <- Git.Config.read =<< Git.Construct.fromPath repo-		waiturl $ gitAnnexUrlFile r+		r <- Git.Config.read =<< Git.Construct.fromPath (toRawFilePath repo)+		waiturl $ fromRawFilePath $ gitAnnexUrlFile r 	waiturl urlfile = do 		v <- tryIO $ readFile urlfile 		case v of
Assistant/Ssh.hs view
@@ -244,10 +244,11 @@ installSshKeyPair :: SshKeyPair -> SshData -> IO SshData installSshKeyPair sshkeypair sshdata = do 	sshdir <- sshDir-	createDirectoryIfMissing True $ parentDir $ sshdir </> sshPrivKeyFile sshdata+	createDirectoryIfMissing True $ fromRawFilePath $+		parentDir $ toRawFilePath $ sshdir </> sshPrivKeyFile sshdata  	unlessM (doesFileExist $ sshdir </> sshPrivKeyFile sshdata) $-		writeFileProtected (sshdir </> sshPrivKeyFile sshdata) (sshPrivKey sshkeypair)+		writeFileProtected (toRawFilePath (sshdir </> sshPrivKeyFile sshdata)) (sshPrivKey sshkeypair) 	unlessM (doesFileExist $ sshdir </> sshPubKeyFile sshdata) $ 		writeFile (sshdir </> sshPubKeyFile sshdata) (sshPubKey sshkeypair) @@ -330,7 +331,7 @@ 			, "Host " ++ mangledhost 			] ++ map (\(k, v) -> "\t" ++ k ++ " " ++ v) 				(settings ++ config)-		setSshConfigMode configfile+		setSshConfigMode (toRawFilePath configfile)  	return $ sshdata 		{ sshHostName = T.pack mangledhost
Assistant/Threads/Committer.hs view
@@ -57,10 +57,11 @@ 	liftAnnex $ do 		-- Clean up anything left behind by a previous process 		-- on unclean shutdown.-		void $ liftIO $ tryIO $ removeDirectoryRecursive lockdowndir+		void $ liftIO $ tryIO $ removeDirectoryRecursive+			(fromRawFilePath lockdowndir) 		void $ createAnnexDirectory lockdowndir 	waitChangeTime $ \(changes, time) -> do-		readychanges <- handleAdds lockdowndir havelsof delayadd $+		readychanges <- handleAdds (fromRawFilePath lockdowndir) havelsof delayadd $ 			simplifyChanges changes 		if shouldCommit False time (length readychanges) readychanges 			then do@@ -261,7 +262,7 @@ 	let (pending, inprocess) = partition isPendingAddChange incomplete 	let lockdownconfig = LockDownConfig 		{ lockingFile = False-		, hardlinkFileTmpDir = Just lockdowndir+		, hardlinkFileTmpDir = Just (toRawFilePath lockdowndir) 		} 	(postponed, toadd) <- partitionEithers 		<$> safeToAdd lockdowndir lockdownconfig havelsof delayadd pending inprocess@@ -304,7 +305,7 @@ 		delta <- liftAnnex getTSDelta 		let cfg = LockDownConfig 			{ lockingFile = False-			, hardlinkFileTmpDir = Just lockdowndir+			, hardlinkFileTmpDir = Just (toRawFilePath lockdowndir) 			} 		if M.null m 			then forM toadd (add cfg)
Assistant/Threads/Merger.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Assistant.Threads.Merger where  import Assistant.Common@@ -13,6 +15,7 @@ import Assistant.Sync import Utility.DirWatcher import Utility.DirWatcher.Types+import Utility.Directory.Create import Annex.CurrentBranch import qualified Annex import qualified Annex.Branch@@ -21,13 +24,15 @@ import qualified Git.Ref import qualified Command.Sync +import qualified System.FilePath.ByteString as P+ {- This thread watches for changes to .git/refs/, and handles incoming  - pushes. -} mergeThread :: NamedThread mergeThread = namedThread "Merger" $ do 	g <- liftAnnex gitRepo-	let gitd = fromRawFilePath (Git.localGitDir g)-	let dir = gitd </> "refs"+	let gitd = Git.localGitDir g+	let dir = gitd P.</> "refs" 	liftIO $ createDirectoryUnder gitd dir 	let hook a = Just <$> asIO2 (runHandler a) 	changehook <- hook onChange@@ -37,8 +42,8 @@ 		, modifyHook = changehook 		, errHook = errhook 		}-	void $ liftIO $ watchDir dir (const False) True hooks id-	debug ["watching", dir]+	void $ liftIO $ watchDir (fromRawFilePath dir) (const False) True hooks id+	debug ["watching", fromRawFilePath dir]  type Handler = FilePath -> Assistant () 
Assistant/Threads/MountWatcher.hs view
@@ -159,7 +159,7 @@  -} remotesUnder :: FilePath -> Assistant [Remote] remotesUnder dir = do-	repotop <- liftAnnex $ fromRawFilePath <$> fromRepo Git.repoPath+	repotop <- liftAnnex $ fromRepo Git.repoPath 	rs <- liftAnnex remoteList 	pairs <- liftAnnex $ mapM (checkremote repotop) rs 	let (waschanged, rs') = unzip pairs@@ -169,7 +169,7 @@ 	return $ mapMaybe snd $ filter fst pairs   where 	checkremote repotop r = case Remote.localpath r of-		Just p | dirContains dir (absPathFrom repotop p) ->+		Just p | dirContains (toRawFilePath dir) (absPathFrom repotop (toRawFilePath p)) -> 			(,) <$> pure True <*> updateRemote r 		_ -> return (False, Just r) 
Assistant/Threads/SanityChecker.hs view
@@ -42,6 +42,7 @@ import Annex.Path import Annex.Tmp import qualified Annex+import qualified Utility.RawFilePath as R #ifdef WITH_WEBAPP import Assistant.WebApp.Types #endif@@ -66,7 +67,7 @@ 	ifM (not <$> liftAnnex (inRepo checkIndexFast)) 		( do 			notice ["corrupt index file found at startup; removing and restaging"]-			liftAnnex $ inRepo $ nukeFile . indexFile+			liftAnnex $ inRepo $ removeWhenExistsWith R.removeLink . indexFile 			{- Normally the startup scan avoids re-staging files, 			 - but with the index deleted, everything needs to be 			 - restaged. -}@@ -80,7 +81,7 @@ 	 - will be automatically regenerated. -} 	unlessM (liftAnnex $ Annex.Branch.withIndex $ inRepo $ Git.Repair.checkIndexFast) $ do 		notice ["corrupt annex/index file found at startup; removing"]-		liftAnnex $ liftIO . nukeFile =<< fromRepo gitAnnexIndex+		liftAnnex $ liftIO . removeWhenExistsWith R.removeLink =<< fromRepo gitAnnexIndex  	{- Fix up ssh remotes set up by past versions of the assistant. -} 	liftIO $ fixUpSshRemotes@@ -221,9 +222,9 @@  -} checkLogSize :: Int -> Assistant () checkLogSize n = do-	f <- liftAnnex $ fromRepo gitAnnexDaemonLogFile+	f <- liftAnnex $ fromRawFilePath <$> fromRepo gitAnnexDaemonLogFile 	logs <- liftIO $ listLogs f-	totalsize <- liftIO $ sum <$> mapM getFileSize logs+	totalsize <- liftIO $ sum <$> mapM (getFileSize . toRawFilePath) logs 	when (totalsize > 2 * oneMegabyte) $ do 		notice ["Rotated logs due to size:", show totalsize] 		liftIO $ openLog f >>= handleToFd >>= redirLog
Assistant/Threads/TransferPoller.hs view
@@ -47,7 +47,7 @@ 		| otherwise = do 			let f = transferFile t g 			mi <- liftIO $ catchDefaultIO Nothing $-				readTransferInfoFile Nothing f+				readTransferInfoFile Nothing (fromRawFilePath f) 			maybe noop (newsize t info . bytesComplete) mi  	newsize t info sz
Assistant/Threads/TransferWatcher.hs view
@@ -37,7 +37,7 @@ 		, modifyHook = modifyhook 		, errHook = errhook 		}-	void $ liftIO $ watchDir dir (const False) True hooks id+	void $ liftIO $ watchDir (fromRawFilePath dir) (const False) True hooks id 	debug ["watching for transfers"]  type Handler = FilePath -> Assistant ()
Assistant/Threads/UpgradeWatcher.hs view
@@ -46,7 +46,7 @@ 			, modifyHook = changed 			, delDirHook = changed 			}-		let dir = parentDir flagfile+		let dir = fromRawFilePath (parentDir (toRawFilePath flagfile)) 		let depth = length (splitPath dir) + 1 		let nosubdirs f = length (splitPath f) == depth 		void $ liftIO $ watchDir dir nosubdirs False hooks (startup mvar)
Assistant/Threads/Watcher.hs view
@@ -24,6 +24,7 @@ import Utility.DirWatcher import Utility.DirWatcher.Types import Utility.InodeCache+import qualified Utility.RawFilePath as R import qualified Annex import qualified Annex.Queue import qualified Git@@ -169,7 +170,7 @@ 	ig _ = False  unlessIgnored :: FilePath -> Assistant (Maybe Change) -> Assistant (Maybe Change)-unlessIgnored file a = ifM (liftAnnex $ checkIgnored (CheckGitIgnore True) file)+unlessIgnored file a = ifM (liftAnnex $ checkIgnored (CheckGitIgnore True) (toRawFilePath file)) 	( noChange 	, a 	)@@ -194,7 +195,7 @@  {- Small files are added to git as-is, while large ones go into the annex. -} add :: GetFileMatcher -> FilePath -> Assistant (Maybe Change)-add largefilematcher file = ifM (liftAnnex $ checkFileMatcher largefilematcher file)+add largefilematcher file = ifM (liftAnnex $ checkFileMatcher largefilematcher (toRawFilePath file)) 	( pendingAddChange file 	, do 		liftAnnex $ Annex.Queue.addCommand "add"@@ -217,7 +218,8 @@ 			=<< inRepo (toTopFilePath (toRawFilePath file)) 	samefilestatus key file status = do 		cache <- Database.Keys.getInodeCaches key-		curr <- withTSDelta $ \delta -> liftIO $ toInodeCache delta file status+		curr <- withTSDelta $ \delta ->+			liftIO $ toInodeCache delta (toRawFilePath file) status 		case (cache, curr) of 			(_, Just c) -> elemInodeCaches c cache 			([], Nothing) -> return True@@ -280,7 +282,7 @@ 						Nothing -> noop 						Just key -> liftAnnex $ 							addassociatedfile key file-					onAddSymlink' (Just $ fromRawFilePath lt) mk file fs+					onAddSymlink' (Just lt) mk file fs  {- A symlink might be an arbitrary symlink, which is just added.  - Or, if it is a git-annex symlink, ensure it points to the content@@ -288,15 +290,17 @@  -} onAddSymlink :: Handler onAddSymlink file filestatus = unlessIgnored file $ do-	linktarget <- liftIO (catchMaybeIO $ readSymbolicLink file)-	kv <- liftAnnex (lookupKey (toRawFilePath file))+	linktarget <- liftIO (catchMaybeIO $ R.readSymbolicLink file')+	kv <- liftAnnex (lookupKey file') 	onAddSymlink' linktarget kv file filestatus+  where+	file' = toRawFilePath file -onAddSymlink' :: Maybe String -> Maybe Key -> Handler+onAddSymlink' :: Maybe LinkTarget -> Maybe Key -> Handler onAddSymlink' linktarget mk file filestatus = go mk   where 	go (Just key) = do-		link <- liftAnnex $ calcRepo $ gitAnnexLink file key+		link <- liftAnnex $ calcRepo $ gitAnnexLink (toRawFilePath file) key 		if linktarget == Just link 			then ensurestaged (Just link) =<< getDaemonStatus 			else do@@ -326,16 +330,17 @@ 	ensurestaged Nothing _ = noChange  {- For speed, tries to reuse the existing blob for symlink target. -}-addLink :: FilePath -> FilePath -> Maybe Key -> Assistant (Maybe Change)+addLink :: FilePath -> LinkTarget -> Maybe Key -> Assistant (Maybe Change) addLink file link mk = do 	debug ["add symlink", file] 	liftAnnex $ do 		v <- catObjectDetails $ Ref $ encodeBS' $ ':':file 		case v of 			Just (currlink, sha, _type)-				| s2w8 link == L.unpack currlink ->+				| L.fromStrict link == currlink -> 					stageSymlink (toRawFilePath file) sha-			_ -> stageSymlink (toRawFilePath file) =<< hashSymlink link+			_ -> stageSymlink (toRawFilePath file)+				=<< hashSymlink link 	madeChange file $ LinkChange mk  onDel :: Handler
Assistant/Threads/WebApp.hs view
@@ -91,7 +91,9 @@ 		else do 			htmlshim <- getAnnex' $ fromRepo gitAnnexHtmlShim 			urlfile <- getAnnex' $ fromRepo gitAnnexUrlFile-			go tlssettings addr webapp htmlshim (Just urlfile)+			go tlssettings addr webapp+				(fromRawFilePath htmlshim)+				(Just urlfile)   where 	-- The webapp thread does not wait for the startupSanityCheckThread 	-- to finish, so that the user interface remains responsive while@@ -100,8 +102,7 @@ 	getreldir 		| noannex = return Nothing 		| otherwise = Just <$>-			(relHome =<< absPath . fromRawFilePath-				=<< getAnnex' (fromRepo repoPath))+			(relHome . fromRawFilePath =<< absPath =<< getAnnex' (fromRepo repoPath)) 	go tlssettings addr webapp htmlshim urlfile = do 		let url = myUrl tlssettings webapp addr 		maybe noop (`writeFileProtected` url) urlfile
Assistant/Upgrade.hs view
@@ -113,16 +113,16 @@ 	| transferDirection t == Download = do 		debug ["finished downloading git-annex distribution"] 		maybe (failedupgrade "bad download") go-			=<< liftAnnex (withObjectLoc k (fsckit . fromRawFilePath))+			=<< liftAnnex (withObjectLoc k fsckit) 	| otherwise = cleanup   where 	k = mkKey $ const $ distributionKey d 	fsckit f = Backend.maybeLookupBackendVariety (fromKey keyVariety k) >>= \case-		Nothing -> return $ Just f+		Nothing -> return $ Just (fromRawFilePath f) 		Just b -> case Types.Backend.verifyKeyContent b of-			Nothing -> return $ Just f+			Nothing -> return $ Just (fromRawFilePath f) 			Just verifier -> ifM (verifier k f)-				( return $ Just f+				( return $ Just (fromRawFilePath f) 				, return Nothing 				) 	go f = do@@ -163,7 +163,7 @@ 	{- OS X uses a dmg, so mount it, and copy the contents into place. -} 	unpack = liftIO $ do 		olddir <- oldVersionLocation-		withTmpDirIn (parentDir newdir) "git-annex.upgrade" $ \tmpdir -> do+		withTmpDirIn (fromRawFilePath (parentDir (toRawFilePath newdir))) "git-annex.upgrade" $ \tmpdir -> do 			void $ boolSystem "hdiutil" 				[ Param "attach", File distributionfile 				, Param "-mountpoint", File tmpdir@@ -188,7 +188,7 @@ 	 - into place. -} 	unpack = liftIO $ do 		olddir <- oldVersionLocation-		withTmpDirIn (parentDir newdir) "git-annex.upgrade" $ \tmpdir -> do+		withTmpDirIn (fromRawFilePath $ parentDir $ toRawFilePath newdir) "git-annex.upgrade" $ \tmpdir -> do 			let tarball = tmpdir </> "tar" 			-- Cannot rely on filename extension, and this also 			-- avoids problems if tar doesn't support transparent@@ -219,8 +219,8 @@ 		unlessM (doesDirectoryExist dir) $ 			error $ "did not find " ++ dir ++ " in " ++ distributionfile 	makeorigsymlink olddir = do-		let origdir = parentDir olddir </> installBase-		nukeFile origdir+		let origdir = fromRawFilePath (parentDir (toRawFilePath olddir)) </> installBase+		removeWhenExistsWith removeLink origdir 		createSymbolicLink newdir origdir  {- Finds where the old version was installed. -}@@ -228,7 +228,7 @@ oldVersionLocation = readProgramFile >>= \case 	Nothing -> error "Cannot find old distribution bundle; not upgrading." 	Just pf -> do-		let pdir = parentDir pf+		let pdir = fromRawFilePath $ parentDir $ toRawFilePath pf #ifdef darwin_HOST_OS 		let dirs = splitDirectories pdir 		{- It will probably be deep inside a git-annex.app directory. -}@@ -257,7 +257,7 @@ 			return Nothing   where 	s = installBase ++ "." ++ distributionVersion d-	topdir = parentDir olddir+	topdir = fromRawFilePath $ parentDir $ toRawFilePath olddir 	newloc = topdir </> s 	trymkdir dir fallback = 		(createDirectory dir >> return (Just dir))@@ -278,8 +278,8 @@ deleteFromManifest :: FilePath -> IO () deleteFromManifest dir = do 	fs <- map (dir </>) . lines <$> catchDefaultIO "" (readFile manifest)-	mapM_ nukeFile fs-	nukeFile manifest+	mapM_ (removeWhenExistsWith removeLink) fs+	removeWhenExistsWith removeLink manifest 	removeEmptyRecursive dir   where 	manifest = dir </> "git-annex.MANIFEST"
Assistant/WebApp/Configurators/Delete.hs view
@@ -16,7 +16,7 @@ import Assistant.Sync import qualified Remote import qualified Git-import Config.Files+import Config.Files.AutoStart import Logs.Trust import Logs.Remote import Logs.PreferredContent@@ -90,7 +90,8 @@ 				mapM_ (\r -> changeSyncable (Just r) False) rs  			liftAnnex $ prepareRemoveAnnexDir dir-			liftIO $ removeDirectoryRecursive =<< absPath dir+			liftIO $ removeDirectoryRecursive . fromRawFilePath+				=<< absPath (toRawFilePath dir) 			 			redirect ShutdownConfirmedR 		_ -> $(widgetFile "configurators/delete/currentrepository")
Assistant/WebApp/Configurators/Edit.hs view
@@ -247,7 +247,7 @@ 		RepoGroupStandard gr -> case associatedDirectory repoconfig gr of 			Just d -> do 				top <- fromRawFilePath <$> fromRepo Git.repoPath-				createWorkTreeDirectory (top </> d)+				createWorkTreeDirectory (toRawFilePath (top </> d)) 			Nothing -> noop 		_ -> noop 
Assistant/WebApp/Configurators/Local.hs view
@@ -20,7 +20,7 @@ import qualified Git import qualified Git.Config import qualified Git.Command-import Config.Files+import Config.Files.AutoStart import Utility.FreeDesktop import Utility.DiskFree #ifndef mingw32_HOST_OS@@ -78,8 +78,8 @@ checkRepositoryPath p = do 	home <- myHomeDir 	let basepath = expandTilde home $ T.unpack p-	path <- absPath basepath-	let parent = parentDir path+	path <- fromRawFilePath <$> absPath (toRawFilePath basepath)+	let parent = fromRawFilePath $ parentDir (toRawFilePath path) 	problems <- catMaybes <$> mapM runcheck 		[ (return $ path == "/", "Enter the full path to use for the repository.") 		, (return $ all isSpace basepath, "A blank path? Seems unlikely.")@@ -354,7 +354,9 @@ combineRepos dir name = liftAnnex $ do 	hostname <- fromMaybe "host" <$> liftIO getHostname 	mylocation <- fromRepo Git.repoLocation-	mypath <- liftIO $ relPathDirToFile dir mylocation+	mypath <- liftIO $ fromRawFilePath <$> relPathDirToFile+		(toRawFilePath dir)+		(toRawFilePath mylocation) 	liftIO $ inDir dir $ void $ makeGitRemote hostname mypath 	addRemote $ makeGitRemote name dir @@ -415,7 +417,9 @@ canWrite :: FilePath -> IO Bool		 canWrite dir = do 	tocheck <- ifM (doesDirectoryExist dir)-		(return dir, return $ parentDir dir)+		( return dir+		, return $ fromRawFilePath $ parentDir $ toRawFilePath dir+		) 	catchBoolIO $ fileAccess tocheck False True False  {- Gets the UUID of the git repo at a location, which may not exist, or
Assistant/WebApp/Configurators/Preferences.hs view
@@ -16,7 +16,7 @@ import qualified Annex import qualified Git import Config-import Config.Files+import Config.Files.AutoStart import Annex.NumCopies import Utility.DataUnits import Git.Config@@ -24,6 +24,7 @@ import qualified BuildInfo  import qualified Data.Text as T+import qualified System.FilePath.ByteString as P  data PrefsForm = PrefsForm 	{ diskReserve :: Text@@ -118,5 +119,6 @@  inAutoStartFile :: Annex Bool inAutoStartFile = do-	here <- liftIO . absPath . fromRawFilePath =<< fromRepo Git.repoPath-	any (`equalFilePath` here) <$> liftIO readAutoStartFile+	here <- liftIO . absPath =<< fromRepo Git.repoPath+	any (`P.equalFilePath` here) . map toRawFilePath+		<$> liftIO readAutoStartFile
Assistant/WebApp/Configurators/Ssh.hs view
@@ -391,7 +391,7 @@ 			Nothing -> go [passwordprompts 0] Nothing 			Just pass -> withTmpFile "ssh" $ \passfile h -> do 				hClose h-				writeFileProtected passfile pass+				writeFileProtected (toRawFilePath passfile) pass 				environ <- getEnvironment 				let environ' = addEntries 					[ ("SSH_ASKPASS", program)
Assistant/WebApp/Control.hs view
@@ -73,6 +73,6 @@ getLogR :: Handler Html getLogR = page "Logs" Nothing $ do 	logfile <- liftAnnex $ fromRepo gitAnnexDaemonLogFile-	logs <- liftIO $ listLogs logfile+	logs <- liftIO $ listLogs (fromRawFilePath logfile) 	logcontent <- liftIO $ concat <$> mapM readFile logs 	$(widgetFile "control/log")
Assistant/WebApp/DashBoard.hs view
@@ -118,8 +118,8 @@  - blocking the response to the browser on it. -} openFileBrowser :: Handler Bool openFileBrowser = do-	path <- liftIO . absPath . fromRawFilePath-		=<< liftAnnex (fromRepo Git.repoPath)+	path <- fromRawFilePath +		<$> (liftIO . absPath =<< liftAnnex (fromRepo Git.repoPath)) #ifdef darwin_HOST_OS 	let cmd = "open" 	let p = proc cmd [path]
Assistant/WebApp/OtherRepos.hs view
@@ -12,9 +12,10 @@ import Assistant.Common import Assistant.WebApp.Types import Assistant.WebApp.Page-import Config.Files+import Config.Files.AutoStart import Utility.Yesod import Assistant.Restart+import qualified Utility.RawFilePath as R  getRepositorySwitcherR :: Handler Html getRepositorySwitcherR = page "Switch repository" Nothing $ do@@ -24,9 +25,9 @@ listOtherRepos :: IO [(String, String)] listOtherRepos = do 	dirs <- readAutoStartFile-	pwd <- getCurrentDirectory+	pwd <- R.getCurrentDirectory 	gooddirs <- filterM isrepo $-		filter (\d -> not $ d `dirContains` pwd) dirs+		filter (\d -> not $ toRawFilePath d `dirContains` pwd) dirs 	names <- mapM relHome gooddirs 	return $ sort $ zip names gooddirs   where
Backend.hs view
@@ -88,7 +88,7 @@ {- Looks up the backend that should be used for a file.  - That can be configured on a per-file basis in the gitattributes file,  - or forced with --backend. -}-chooseBackend :: FilePath -> Annex (Maybe Backend)+chooseBackend :: RawFilePath -> Annex (Maybe Backend) chooseBackend f = Annex.getState Annex.forcebackend >>= go   where 	go Nothing = maybeLookupBackendVariety . parseKeyVariety . encodeBS
Backend/External.hs view
@@ -102,12 +102,12 @@ 		return $ GetNextMessage go 	go _ = Nothing -verifyKeyContentExternal :: ExternalBackendName -> HasExt -> MeterUpdate -> Key -> FilePath -> Annex Bool+verifyKeyContentExternal :: ExternalBackendName -> HasExt -> MeterUpdate -> Key -> RawFilePath -> Annex Bool verifyKeyContentExternal ebname hasext meterupdate k f =  	withExternalState ebname hasext $ \st -> 		handleRequest st req notavail go   where-	req = VERIFYKEYCONTENT (toProtoKey k) f+	req = VERIFYKEYCONTENT (toProtoKey k) (fromRawFilePath f)  	-- This should not be able to happen, because CANVERIFY is checked 	-- before this function is enable, and so the external program 
Backend/Hash.hs view
@@ -15,12 +15,13 @@  import Annex.Common import qualified Annex+import Backend.Utilities import Types.Key import Types.Backend import Types.KeySource import Utility.Hash import Utility.Metered-import Backend.Utilities+import qualified Utility.RawFilePath as R  import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8@@ -100,7 +101,7 @@ {- A key is a hash of its contents. -} keyValue :: Hash -> KeySource -> MeterUpdate -> Annex Key keyValue hash source meterupdate = do-	let file = fromRawFilePath (contentLocation source)+	let file = contentLocation source 	filesize <- liftIO $ getFileSize file 	s <- hashFile hash file meterupdate 	return $ mkKey $ \k -> k@@ -117,10 +118,10 @@  {- A key's checksum is checked during fsck when it's content is present  - except for in fast mode. -}-checkKeyChecksum :: Hash -> Key -> FilePath -> Annex Bool+checkKeyChecksum :: Hash -> Key -> RawFilePath -> Annex Bool checkKeyChecksum hash key file = catchIOErrorType HardwareFault hwfault $ do 	fast <- Annex.getState Annex.fast-	exists <- liftIO $ doesFileExist file+	exists <- liftIO $ R.doesPathExist file 	case (exists, fast) of 		(True, False) -> do 			showAction "checksum"@@ -191,9 +192,9 @@ 	oldvariety = fromKey keyVariety oldkey 	newvariety = backendVariety newbackend -hashFile :: Hash -> FilePath -> MeterUpdate -> Annex String+hashFile :: Hash -> RawFilePath -> MeterUpdate -> Annex String hashFile hash file meterupdate = -	liftIO $ withMeteredFile file meterupdate $ \b -> do+	liftIO $ withMeteredFile (fromRawFilePath file) meterupdate $ \b -> do 		let h = hasher b 		-- Force full evaluation of hash so whole file is read 		-- before returning.
Backend/WORM.hs view
@@ -39,7 +39,7 @@ keyValue source _ = do 	let f = contentLocation source 	stat <- liftIO $ R.getFileStatus f-	sz <- liftIO $ getFileSize' (fromRawFilePath f) stat+	sz <- liftIO $ getFileSize' f stat 	relf <- fromRawFilePath . getTopFilePath 		<$> inRepo (toTopFilePath $ keyFilename source) 	return $ mkKey $ \k -> k
Build/DesktopFile.hs view
@@ -16,6 +16,7 @@ import Utility.Path import Utility.Monad import Utility.Directory+import Utility.FileSystemEncoding import Config.Files import Utility.OSX import Assistant.Install.AutoStart@@ -77,7 +78,7 @@ 		( return () 		, do 			programfile <- inDestDir =<< programFile-			createDirectoryIfMissing True (parentDir programfile)+			createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath programfile))) 			writeFile programfile command 		) 
CHANGELOG view
@@ -1,3 +1,18 @@+git-annex (8.20201116) upstream; urgency=medium++  * move: Fix a regression in the last release that made move --to not+    honor numcopies settings.+  * sync --content: Fix a bug where a file that was not preferred content+    could be transferred to a remote. This happened when the file got deleted+    after the sync started running.+  * Warn when adding a annex symlink or pointer file that uses a key that+    is not known to the repository, to prevent confusion if the user has+    copied it from some other repository.+  * examinekey: Added two new format variables: objectpath and objectpointer+  * examinekey: Added --migrate-to-backend++ -- Joey Hess <id@joeyh.name>  Mon, 16 Nov 2020 09:36:35 -0400+ git-annex (8.20201103) upstream; urgency=medium    * move: Improve resuming a move that was interrupted after the object
CmdLine/Batch.hs view
@@ -137,7 +137,7 @@ 			)   where 	go a' = batchInput fmt -		(Right <$$> liftIO . relPathCwdToFile)+		(Right . fromRawFilePath <$$> liftIO . relPathCwdToFile . toRawFilePath) 		(batchCommandAction . uncurry a')  batchAnnexedFilesMatching :: BatchFormat -> AnnexedFileSeeker -> Annex ()
CmdLine/GitAnnexShell.hs view
@@ -124,7 +124,8 @@ 		"Restricted login shell for git-annex only SSH access"   where 	mkrepo = do-		r <- Git.Construct.repoAbsPath dir >>= Git.Construct.fromAbsPath+		r <- Git.Construct.repoAbsPath (toRawFilePath dir)+			>>= Git.Construct.fromAbsPath 		Git.Config.read r 			`catchIO` \_ -> do 				hn <- fromMaybe "unknown" <$> getHostname
CmdLine/GitAnnexShell/Checks.hs view
@@ -71,7 +71,9 @@ 	canondir home d 		| "~/" `isPrefixOf` d = return d 		| "/~/" `isPrefixOf` d = return $ drop 1 d-		| otherwise = relHome $ absPathFrom home d+		| otherwise = relHome $ fromRawFilePath $ absPathFrom +			(toRawFilePath home)+			(toRawFilePath d)  {- Modifies a Command to check that it is run in either a git-annex  - repository, or a repository with a gcrypt-id set. -}
CmdLine/Seek.hs view
@@ -25,6 +25,7 @@ import Git.FilePath import qualified Limit import CmdLine.GitAnnex.Options+import CmdLine.Action import Logs import Logs.Unused import Types.Transfer@@ -44,11 +45,11 @@ import qualified Database.Keys import qualified Utility.RawFilePath as R import Utility.Tuple-import CmdLine.Action  import Control.Concurrent.Async import System.Posix.Types import Data.IORef+import qualified System.FilePath.ByteString as P  data AnnexedFileSeeker = AnnexedFileSeeker 	{ startAction :: SeekInput -> RawFilePath -> Key -> CommandStart@@ -92,7 +93,7 @@ 	seekFiltered (const (pure True)) a $ 		seekHelper id ww (const $ LsFiles.notInRepo [] include_ignored) l -withPathContents :: ((FilePath, FilePath) -> CommandSeek) -> CmdParams -> CommandSeek+withPathContents :: ((RawFilePath, RawFilePath) -> CommandSeek) -> CmdParams -> CommandSeek withPathContents a params = do 	matcher <- Limit.getMatcher 	forM_ params $ \p -> do@@ -102,13 +103,18 @@ 				a f   where 	get p = ifM (isDirectory <$> getFileStatus p)-		( map (\f -> (f, makeRelative (parentDir p) f))+		( map (\f -> +			let f' = toRawFilePath f+			in (f', P.makeRelative (P.takeDirectory (P.dropTrailingPathSeparator p')) f')) 			<$> dirContentsRecursiveSkipping (".git" `isSuffixOf`) True p-		, return [(p, takeFileName p)]+		, return [(p', P.takeFileName p')] 		)+	  where+		p' = toRawFilePath p+ 	checkmatch matcher (f, relf) = matcher $ MatchingFile $ FileInfo-		{ contentFile = Just (toRawFilePath f)-		, matchFile = toRawFilePath relf+		{ contentFile = Just f+		, matchFile = relf 		}  withWords :: ([String] -> CommandSeek) -> CmdParams -> CommandSeek@@ -490,7 +496,7 @@ 		currbranch <- getCurrentBranch 		stopattop <- prepviasymlink 		ps' <- flip filterM ps $ \p -> do-			relf <- liftIO $ relPathCwdToFile p+			relf <- liftIO $ relPathCwdToFile $ toRawFilePath p 			ifM (not <$> (exists p <||> hidden currbranch relf)) 				( prob (p ++ " not found") 				, ifM (viasymlink stopattop (upFrom relf))@@ -517,7 +523,7 @@  	viasymlink _ Nothing = return False 	viasymlink stopattop (Just p) = do-		st <- liftIO $ getSymbolicLinkStatus p+		st <- liftIO $ R.getSymbolicLinkStatus p 		if stopattop st 			then return False 			else if isSymbolicLink st@@ -526,7 +532,7 @@  	hidden currbranch f 		| allowhidden = isJust-			<$> catObjectMetaDataHidden (toRawFilePath f) currbranch+			<$> catObjectMetaDataHidden f currbranch 		| otherwise = return False  	prob msg = do
Command.hs view
@@ -129,7 +129,8 @@ noDaemonRunning = addCheck $ whenM (isJust <$> daemonpid) $ 	giveup "You cannot run this command while git-annex watch or git-annex assistant is running."   where-	daemonpid = liftIO . checkDaemon =<< fromRepo gitAnnexPidFile+	daemonpid = liftIO . checkDaemon . fromRawFilePath+		=<< fromRepo gitAnnexPidFile  dontCheck :: CommandCheck -> Command -> Command dontCheck check cmd = mutateCheck cmd $ \c -> filter (/= check) c
Command/Add.hs view
@@ -81,8 +81,9 @@ 	annexdotfiles <- getGitConfigVal annexDotFiles  	let gofile (si, file) = case largeFilesOverride o of 		Nothing -> -			let file' = fromRawFilePath file-			in ifM (pure (annexdotfiles || not (dotfile file')) <&&> (checkFileMatcher largematcher file' <||> Annex.getState Annex.force))+			ifM (pure (annexdotfiles || not (dotfile file))+				<&&> (checkFileMatcher largematcher file +				<||> Annex.getState Annex.force)) 				( start o si file addunlockedmatcher 				, ifM (annexAddSmallFiles <$> Annex.getGitConfig) 					( startSmall o si file@@ -128,20 +129,19 @@ addSmallOverridden :: AddOptions -> RawFilePath -> Annex Bool addSmallOverridden o file = do 	showNote "adding content to git repository"-	let file' = fromRawFilePath file-	s <- liftIO $ getSymbolicLinkStatus file'+	s <- liftIO $ R.getSymbolicLinkStatus file 	if not (isRegularFile s) 		then addFile (checkGitIgnoreOption o) file 		else do 			-- Can't use addFile because the clean filter will 			-- honor annex.largefiles and it has been overridden. 			-- Instead, hash the file and add to the index.-			sha <- hashFile file'+			sha <- hashFile file 			let ty = if isExecutable (fileMode s) 				then TreeExecutable 				else TreeFile 			Annex.Queue.addUpdateIndex =<<-				inRepo (Git.UpdateIndex.stageFile sha ty file')+				inRepo (Git.UpdateIndex.stageFile sha ty (fromRawFilePath file)) 			return True  addFile :: CheckGitIgnore -> RawFilePath -> Annex Bool@@ -169,16 +169,17 @@ 		liftIO (catchMaybeIO $ R.getSymbolicLinkStatus file) >>= \case 			Just s | isSymbolicLink s -> fixuplink key 			_ -> add-	fixuplink key = starting "add" (ActionItemWorkTreeFile file) si $ do-		-- the annexed symlink is present but not yet added to git-		liftIO $ removeFile (fromRawFilePath file)-		addLink (checkGitIgnoreOption o) (fromRawFilePath file) key Nothing-		next $-			cleanup key =<< inAnnex key-	fixuppointer key = starting "add" (ActionItemWorkTreeFile file) si $ do-		-- the pointer file is present, but not yet added to git-		Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file)-		next $ addFile (checkGitIgnoreOption o) file+	fixuplink key = +		starting "add" (ActionItemWorkTreeFile file) si $+			addingExistingLink file key $ do+				liftIO $ removeFile (fromRawFilePath file)+				addLink (checkGitIgnoreOption o) file key Nothing+				next $ cleanup key =<< inAnnex key+	fixuppointer key =+		starting "add" (ActionItemWorkTreeFile file) si $+			addingExistingLink file key $ do+				Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file)+				next $ addFile (checkGitIgnoreOption o) file  perform :: AddOptions -> RawFilePath -> AddUnlockedMatcher -> CommandPerform perform o file addunlockedmatcher = withOtherTmp $ \tmpdir -> do
Command/AddUnused.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Command.AddUnused where  import Logs.Location@@ -33,7 +35,7 @@ 	addLink (CheckGitIgnore False) file key Nothing 	return True   where-	file = "unused." ++ fromRawFilePath (keyFile key)+	file = "unused." <> keyFile key  {- The content is not in the annex, but in another directory, and  - it seems better to error out, rather than moving bad/tmp content into
Command/AddUrl.hs view
@@ -7,8 +7,6 @@  module Command.AddUrl where -import Network.URI- import Command import Backend import qualified Annex@@ -32,8 +30,12 @@ import Utility.Metered import Utility.HtmlDetect import Utility.Path.Max+import qualified Utility.RawFilePath as R import qualified Annex.Transfer as Transfer +import Network.URI+import qualified System.FilePath.ByteString as P+ cmd :: Command cmd = notBareRepo $ withGlobalOptions [jobsOption, jsonOptions, jsonProgressOption] $ 	command "addurl" SectionCommon "add urls to annex"@@ -163,14 +165,15 @@ startRemote :: AddUnlockedMatcher -> Remote -> AddUrlOptions -> SeekInput -> FilePath -> URLString -> Maybe Integer -> CommandStart startRemote addunlockedmatcher r o si file uri sz = do 	pathmax <- liftIO $ fileNameLengthLimit "."-	let file' = joinPath $ map (truncateFilePath pathmax) $ splitDirectories file+	let file' = joinPath $ map (truncateFilePath pathmax) $+		splitDirectories file 	startingAddUrl si uri o $ do 		showNote $ "from " ++ Remote.name r  		showDestinationFile file'-		performRemote addunlockedmatcher r o uri file' sz+		performRemote addunlockedmatcher r o uri (toRawFilePath file') sz -performRemote :: AddUnlockedMatcher -> Remote -> AddUrlOptions -> URLString -> FilePath -> Maybe Integer -> CommandPerform-performRemote addunlockedmatcher r o uri file sz = ifAnnexed (toRawFilePath file) adduri geturi+performRemote :: AddUnlockedMatcher -> Remote -> AddUrlOptions -> URLString -> RawFilePath -> Maybe Integer -> CommandPerform+performRemote addunlockedmatcher r o uri file sz = ifAnnexed file adduri geturi   where 	loguri = setDownloader uri OtherDownloader 	adduri = addUrlChecked o loguri file (Remote.uuid r) checkexistssize@@ -179,7 +182,7 @@ 		Just n -> (True, n == fromMaybe n (fromKey keySize key), loguri) 	geturi = next $ isJust <$> downloadRemoteFile addunlockedmatcher r (downloadOptions o) uri file sz -downloadRemoteFile :: AddUnlockedMatcher -> Remote -> DownloadOptions -> URLString -> FilePath -> Maybe Integer -> Annex (Maybe Key)+downloadRemoteFile :: AddUnlockedMatcher -> Remote -> DownloadOptions -> URLString -> RawFilePath -> Maybe Integer -> Annex (Maybe Key) downloadRemoteFile addunlockedmatcher r o uri file sz = checkCanAdd o file $ \canadd -> do 	let urlkey = Backend.URL.fromUrl uri sz 	createWorkTreeDirectory (parentDir file)@@ -200,7 +203,7 @@ 		)   where 	loguri = setDownloader uri OtherDownloader-	af = AssociatedFile (Just (toRawFilePath file))+	af = AssociatedFile (Just file)  startWeb :: AddUnlockedMatcher -> AddUrlOptions -> SeekInput -> URLString -> CommandStart startWeb addunlockedmatcher o si urlstring = go $ fromMaybe bad $ parseURI urlstring@@ -229,7 +232,7 @@ 							, pure f 							) 				_ -> pure $ url2file url (pathdepthOption o) pathmax-		performWeb addunlockedmatcher o urlstring file urlinfo+		performWeb addunlockedmatcher o urlstring (toRawFilePath file) urlinfo  sanitizeOrPreserveFilePath :: AddUrlOptions -> FilePath -> Annex FilePath sanitizeOrPreserveFilePath o f@@ -255,8 +258,8 @@ 			, "has a security problem (" ++ d ++ "), not adding." 			] -performWeb :: AddUnlockedMatcher -> AddUrlOptions -> URLString -> FilePath -> Url.UrlInfo -> CommandPerform-performWeb addunlockedmatcher o url file urlinfo = ifAnnexed (toRawFilePath file) addurl geturl+performWeb :: AddUnlockedMatcher -> AddUrlOptions -> URLString -> RawFilePath -> Url.UrlInfo -> CommandPerform+performWeb addunlockedmatcher o url file urlinfo = ifAnnexed file addurl geturl   where 	geturl = next $ isJust <$> addUrlFile addunlockedmatcher (downloadOptions o) url urlinfo file 	addurl = addUrlChecked o url file webUUID $ \k ->@@ -267,11 +270,11 @@  {- Check that the url exists, and has the same size as the key,  - and add it as an url to the key. -}-addUrlChecked :: AddUrlOptions -> URLString -> FilePath -> UUID -> (Key -> Annex (Bool, Bool, URLString)) -> Key -> CommandPerform+addUrlChecked :: AddUrlOptions -> URLString -> RawFilePath -> UUID -> (Key -> Annex (Bool, Bool, URLString)) -> Key -> CommandPerform addUrlChecked o url file u checkexistssize key = 	ifM ((elem url <$> getUrls key) <&&> (elem u <$> loggedLocations key)) 		( do-			showDestinationFile file+			showDestinationFile (fromRawFilePath file) 			next $ return True 		, do 			(exists, samesize, url') <- checkexistssize key@@ -293,49 +296,49 @@  - different file, based on the title of the media. Unless the user  - specified fileOption, which then forces using the FilePath.  -}-addUrlFile :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)+addUrlFile :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> RawFilePath -> Annex (Maybe Key) addUrlFile addunlockedmatcher o url urlinfo file = 	ifM (Annex.getState Annex.fast <||> pure (relaxedOption o)) 		( nodownloadWeb addunlockedmatcher o url urlinfo file 		, downloadWeb addunlockedmatcher o url urlinfo file 		) -downloadWeb :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)+downloadWeb :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> RawFilePath -> Annex (Maybe Key) downloadWeb addunlockedmatcher o url urlinfo file =-	go =<< downloadWith' downloader urlkey webUUID url (AssociatedFile (Just (toRawFilePath file)))+	go =<< downloadWith' downloader urlkey webUUID url (AssociatedFile (Just file))   where 	urlkey = addSizeUrlKey urlinfo $ Backend.URL.fromUrl url Nothing 	downloader f p = Url.withUrlOptions $ downloadUrl urlkey p [url] f 	go Nothing = return Nothing-	go (Just tmp) = ifM (pure (not (rawOption o)) <&&> liftIO (isHtml <$> readFile tmp))+	go (Just tmp) = ifM (pure (not (rawOption o)) <&&> liftIO (isHtml <$> readFile (fromRawFilePath tmp))) 		( tryyoutubedl tmp 		, normalfinish tmp 		) 	normalfinish tmp = checkCanAdd o file $ \canadd -> do-		showDestinationFile file+		showDestinationFile (fromRawFilePath file) 		createWorkTreeDirectory (parentDir file) 		Just <$> finishDownloadWith canadd addunlockedmatcher tmp webUUID url file 	-- Ask youtube-dl what filename it will download first,  	-- so it's only used when the file contains embedded media. 	tryyoutubedl tmp = youtubeDlFileNameHtmlOnly url >>= \case 		Right mediafile -> -			let f = youtubeDlDestFile o file mediafile-			in ifAnnexed (toRawFilePath f)-				(alreadyannexed f)+			let f = youtubeDlDestFile o file (toRawFilePath mediafile)+			in ifAnnexed f+				(alreadyannexed (fromRawFilePath f)) 				(dl f) 		Left _ -> normalfinish tmp 	  where 		dl dest = withTmpWorkDir mediakey $ \workdir -> do-			let cleanuptmp = pruneTmpWorkDirBefore tmp (liftIO . nukeFile)+			let cleanuptmp = pruneTmpWorkDirBefore tmp (liftIO . removeWhenExistsWith R.removeLink) 			showNote "using youtube-dl" 			Transfer.notifyTransfer Transfer.Download url $ 				Transfer.download webUUID mediakey (AssociatedFile Nothing) Transfer.noRetry $ \p ->-					youtubeDl url workdir p >>= \case+					youtubeDl url (fromRawFilePath workdir) p >>= \case 						Right (Just mediafile) -> do 							cleanuptmp 							checkCanAdd o dest $ \canadd -> do-								showDestinationFile dest-								addWorkTree canadd addunlockedmatcher webUUID mediaurl dest mediakey (Just mediafile)+								showDestinationFile (fromRawFilePath dest)+								addWorkTree canadd addunlockedmatcher webUUID mediaurl dest mediakey (Just (toRawFilePath mediafile)) 								return $ Just mediakey 						Right Nothing -> normalfinish tmp 						Left msg -> do@@ -378,34 +381,34 @@  - Downloads the url, sets up the worktree file, and returns the  - real key.  -}-downloadWith :: CanAddFile -> AddUnlockedMatcher -> (FilePath -> MeterUpdate -> Annex Bool) -> Key -> UUID -> URLString -> FilePath -> Annex (Maybe Key)+downloadWith :: CanAddFile -> AddUnlockedMatcher -> (FilePath -> MeterUpdate -> Annex Bool) -> Key -> UUID -> URLString -> RawFilePath -> Annex (Maybe Key) downloadWith canadd addunlockedmatcher downloader dummykey u url file = 	go =<< downloadWith' downloader dummykey u url afile   where-	afile = AssociatedFile (Just (toRawFilePath file))+	afile = AssociatedFile (Just file) 	go Nothing = return Nothing 	go (Just tmp) = Just <$> finishDownloadWith canadd addunlockedmatcher tmp u url file  {- Like downloadWith, but leaves the dummy key content in  - the returned location. -}-downloadWith' :: (FilePath -> MeterUpdate -> Annex Bool) -> Key -> UUID -> URLString -> AssociatedFile -> Annex (Maybe FilePath)+downloadWith' :: (FilePath -> MeterUpdate -> Annex Bool) -> Key -> UUID -> URLString -> AssociatedFile -> Annex (Maybe RawFilePath) downloadWith' downloader dummykey u url afile = 	checkDiskSpaceToGet dummykey Nothing $ do 		tmp <- fromRepo $ gitAnnexTmpObjectLocation dummykey 		ok <- Transfer.notifyTransfer Transfer.Download url $ 			Transfer.download u dummykey afile Transfer.stdRetry $ \p -> do 				createAnnexDirectory (parentDir tmp)-				downloader tmp p+				downloader (fromRawFilePath tmp) p 		if ok 			then return (Just tmp) 			else return Nothing -finishDownloadWith :: CanAddFile -> AddUnlockedMatcher -> FilePath -> UUID -> URLString -> FilePath -> Annex Key+finishDownloadWith :: CanAddFile -> AddUnlockedMatcher -> RawFilePath -> UUID -> URLString -> RawFilePath -> Annex Key finishDownloadWith canadd addunlockedmatcher tmp u url file = do 	backend <- chooseBackend file 	let source = KeySource-		{ keyFilename = toRawFilePath file-		, contentLocation = toRawFilePath tmp+		{ keyFilename = file+		, contentLocation = tmp 		, inodeCache = Nothing 		} 	key <- fst <$> genKey source nullMeterUpdate backend@@ -419,14 +422,16 @@ 	}  {- Adds worktree file to the repository. -}-addWorkTree :: CanAddFile -> AddUnlockedMatcher -> UUID -> URLString -> FilePath -> Key -> Maybe FilePath -> Annex ()+addWorkTree :: CanAddFile -> AddUnlockedMatcher -> UUID -> URLString -> RawFilePath -> Key -> Maybe RawFilePath -> Annex () addWorkTree _ addunlockedmatcher u url file key mtmp = case mtmp of 	Nothing -> go 	Just tmp -> do 		-- Move to final location for large file check. 		pruneTmpWorkDirBefore tmp $ \_ -> do-			createWorkTreeDirectory (takeDirectory file)-			liftIO $ renameFile tmp file+			createWorkTreeDirectory (P.takeDirectory file)+			liftIO $ renameFile +				(fromRawFilePath tmp)+				(fromRawFilePath file) 		largematcher <- largeFilesMatcher 		large <- checkFileMatcher largematcher file 		if large@@ -434,9 +439,11 @@ 				-- Move back to tmp because addAnnexedFile 				-- needs the file in a different location 				-- than the work tree file.-				liftIO $ renameFile file tmp+				liftIO $ renameFile+					(fromRawFilePath file)+					(fromRawFilePath tmp) 				go-			else void $ Command.Add.addSmall noci (toRawFilePath file)+			else void $ Command.Add.addSmall noci file   where 	go = do 		maybeShowJSON $ JSONChunk [("key", serializeKey key)]@@ -446,18 +453,18 @@ 			( do 				when (isJust mtmp) $ 					logStatus key InfoPresent-			, maybe noop (\tmp -> pruneTmpWorkDirBefore tmp (liftIO . nukeFile)) mtmp+			, maybe noop (\tmp -> pruneTmpWorkDirBefore tmp (liftIO . removeWhenExistsWith R.removeLink)) mtmp 			) 	 	-- git does not need to check ignores, because that has already 	-- been done, as witnessed by the CannAddFile. 	noci = CheckGitIgnore False -nodownloadWeb :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)+nodownloadWeb :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> RawFilePath -> Annex (Maybe Key) nodownloadWeb addunlockedmatcher o url urlinfo file 	| Url.urlExists urlinfo = if rawOption o 		then nomedia-		else either (const nomedia) usemedia+		else either (const nomedia) (usemedia . toRawFilePath) 			=<< youtubeDlFileName url 	| otherwise = do 		warning $ "unable to access url: " ++ url@@ -472,14 +479,14 @@ 		let mediakey = Backend.URL.fromUrl mediaurl Nothing 		nodownloadWeb' o addunlockedmatcher mediaurl mediakey dest -youtubeDlDestFile :: DownloadOptions -> FilePath -> FilePath -> FilePath+youtubeDlDestFile :: DownloadOptions -> RawFilePath -> RawFilePath -> RawFilePath youtubeDlDestFile o destfile mediafile 	| isJust (fileOption o) = destfile-	| otherwise = takeFileName mediafile+	| otherwise = P.takeFileName mediafile -nodownloadWeb' :: DownloadOptions -> AddUnlockedMatcher -> URLString -> Key -> FilePath -> Annex (Maybe Key)+nodownloadWeb' :: DownloadOptions -> AddUnlockedMatcher -> URLString -> Key -> RawFilePath -> Annex (Maybe Key) nodownloadWeb' o addunlockedmatcher url key file = checkCanAdd o file $ \canadd -> do-	showDestinationFile file+	showDestinationFile (fromRawFilePath file) 	createWorkTreeDirectory (parentDir file) 	addWorkTree canadd addunlockedmatcher webUUID url file key Nothing 	return (Just key)@@ -515,14 +522,14 @@  data CanAddFile = CanAddFile -checkCanAdd :: DownloadOptions -> FilePath -> (CanAddFile -> Annex (Maybe a)) -> Annex (Maybe a)-checkCanAdd o file a = ifM (isJust <$> (liftIO $ catchMaybeIO $ getSymbolicLinkStatus file))+checkCanAdd :: DownloadOptions -> RawFilePath -> (CanAddFile -> Annex (Maybe a)) -> Annex (Maybe a)+checkCanAdd o file a = ifM (isJust <$> (liftIO $ catchMaybeIO $ R.getSymbolicLinkStatus file)) 	( do-		warning $ file ++ " already exists; not overwriting"+		warning $ fromRawFilePath file ++ " already exists; not overwriting" 		return Nothing 	, ifM (checkIgnored (checkGitIgnoreOption o) file) 		( do-			warning $ "not adding " ++ file ++ " which is .gitignored (use --no-check-gitignore to override)"+			warning $ "not adding " ++ fromRawFilePath file ++ " which is .gitignored (use --no-check-gitignore to override)" 			return Nothing 		, a CanAddFile 		)
Command/Assistant.hs view
@@ -12,6 +12,7 @@ import Annex.Init import Annex.Path import Config.Files+import Config.Files.AutoStart import qualified BuildInfo import Utility.HumanTime import Assistant.Install
Command/Copy.hs view
@@ -72,7 +72,7 @@ 	Command.Move.start (fromToOptions o) Command.Move.RemoveNever si file key   where 	shouldCopy-		| autoMode o = want <||> numCopiesCheck (fromRawFilePath file) key (<)+		| autoMode o = want <||> numCopiesCheck file key (<) 		| otherwise = return True 	want = case fromToOptions o of 		Right (ToRemote dest) ->
Command/DropUnused.hs view
@@ -15,6 +15,7 @@ import Command.Unused (withUnusedMaps, UnusedMaps(..), startUnused) import Annex.NumCopies import Annex.Content+import qualified Utility.RawFilePath as R  cmd :: Command cmd = command "dropunused" SectionMaintenance@@ -63,8 +64,8 @@   where 	droplocal = Command.Drop.performLocal key (AssociatedFile Nothing) numcopies [] -performOther :: (Key -> Git.Repo -> FilePath) -> Key -> CommandPerform+performOther :: (Key -> Git.Repo -> RawFilePath) -> Key -> CommandPerform performOther filespec key = do 	f <- fromRepo $ filespec key-	pruneTmpWorkDirBefore f (liftIO . nukeFile)+	pruneTmpWorkDirBefore f (liftIO . removeWhenExistsWith R.removeLink) 	next $ return True
Command/ExamineKey.hs view
@@ -1,6 +1,6 @@ {- git-annex command  -- - Copyright 2013 Joey Hess <id@joeyh.name>+ - Copyright 2013-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -10,17 +10,70 @@ import Command import qualified Utility.Format import Command.Find (parseFormatOption, showFormatted, keyVars)+import Annex.Link+import Backend+import Types.Backend+import Types.Key +import Data.Char+import qualified Data.ByteString as B+ cmd :: Command cmd = noCommit $ noMessages $ dontCheck repoExists $  	withGlobalOptions [jsonOptions] $ 		command "examinekey" SectionPlumbing  			"prints information from a key" 			(paramRepeating paramKey)-			(batchable run (optional parseFormatOption))+			(batchable run optParser) -run :: Maybe Utility.Format.Format -> SeekInput -> String -> Annex Bool-run format _ p = do-	let k = fromMaybe (giveup "bad key") $ deserializeKey p-	showFormatted format (serializeKey' k) (keyVars k)+data ExamineOptions = ExamineOptions+	{ format :: Maybe Utility.Format.Format+	, migrateToBackend :: Maybe (DeferredParse Backend)+	, associatedFile :: AssociatedFile+	}++optParser :: Parser ExamineOptions+optParser = ExamineOptions+	<$> optional parseFormatOption+	<*> (fmap (DeferredParse . tobackend) <$> migrateopt)+	<*> (AssociatedFile <$> fileopt)+  where+	fileopt = optional $ strOption+		( long "filename" <> metavar paramFile+		<> help "file associated with the key"+		)+	migrateopt = optional $ strOption+		( long "migrate-to-backend" <> metavar paramName+		<> help "migrate key to other backend when possible"+		)+	tobackend = lookupBackendVariety . parseKeyVariety . encodeBS++run :: ExamineOptions -> SeekInput -> String -> Annex Bool+run o _ input = do+	k <- getkey+	+	objectpath <- calcRepo $ gitAnnexLocation k+	let objectpointer = formatPointer k+	showFormatted (format o) (serializeKey' k) $+		[ ("objectpath", fromRawFilePath objectpath)+		, ("objectpointer", fromRawFilePath objectpointer)+		] ++ keyVars k 	return True+  where+	-- Parse the input, which is either a key, or in batch mode +	-- can be "key filename"+	(ikb, ifb) = B.break (== (fromIntegral (ord ' '))) (toRawFilePath input)+	ifb' = B.drop 1 ifb+	ik = fromMaybe (giveup "bad key") (deserializeKey' ikb)+	af = if B.null ifb'+		then associatedFile o+		else AssociatedFile (Just ifb')++	getkey = case migrateToBackend o of+		Nothing -> pure ik+		Just v -> getParsed v >>= \b ->+			maybeLookupBackendVariety (fromKey keyVariety ik) >>= \case+				Just ib -> case fastMigrate ib of+					Just fm -> fromMaybe ik <$> fm ik b af+					Nothing -> pure ik+				Nothing -> pure ik
Command/Fix.hs view
@@ -46,11 +46,10 @@ start :: FixWhat -> SeekInput -> RawFilePath -> Key -> CommandStart start fixwhat si file key = do 	currlink <- liftIO $ catchMaybeIO $ R.readSymbolicLink file-	wantlink <- calcRepo $ gitAnnexLink (fromRawFilePath file) key+	wantlink <- calcRepo $ gitAnnexLink file key 	case currlink of 		Just l-			| l /= toRawFilePath wantlink -> fixby $-				fixSymlink (fromRawFilePath file) wantlink+			| l /=  wantlink -> fixby $ fixSymlink file wantlink 			| otherwise -> stop 		Nothing -> case fixwhat of 			FixAll -> fixthin@@ -73,12 +72,12 @@ breakHardLink :: RawFilePath -> Key -> RawFilePath -> CommandPerform breakHardLink file key obj = do 	replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do+		let tmp' = toRawFilePath tmp 		mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file-		let obj' = fromRawFilePath obj-		unlessM (checkedCopyFile key obj' tmp mode) $+		unlessM (checkedCopyFile key obj tmp' mode) $ 			error "unable to break hard link"-		thawContent tmp-		modifyContent obj' $ freezeContent obj'+		thawContent tmp'+		modifyContent obj $ freezeContent obj 	Database.Keys.storeInodeCaches key [file] 	next $ return True @@ -86,25 +85,25 @@ makeHardLink file key = do 	replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do 		mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file-		linkFromAnnex key tmp mode >>= \case+		linkFromAnnex key (toRawFilePath tmp) mode >>= \case 			LinkAnnexFailed -> error "unable to make hard link" 			_ -> noop 	next $ return True -fixSymlink :: FilePath -> FilePath -> CommandPerform+fixSymlink :: RawFilePath -> RawFilePath -> CommandPerform fixSymlink file link = do #if ! defined(mingw32_HOST_OS) 	-- preserve mtime of symlink 	mtime <- liftIO $ catchMaybeIO $ modificationTimeHiRes-		<$> getSymbolicLinkStatus file+		<$> R.getSymbolicLinkStatus file #endif 	createWorkTreeDirectory (parentDir file)-	liftIO $ removeFile file-	liftIO $ createSymbolicLink link file+	liftIO $ R.removeLink file+	liftIO $ R.createSymbolicLink link file #if ! defined(mingw32_HOST_OS) 	liftIO $ maybe noop (\t -> touch file t False) mtime #endif-	next $ cleanupSymlink file+	next $ cleanupSymlink (fromRawFilePath file)  cleanupSymlink :: FilePath -> CommandCleanup cleanupSymlink file = do
Command/FromKey.hs view
@@ -16,6 +16,7 @@ import Annex.Perms import qualified Annex import qualified Backend.URL+import qualified Utility.RawFilePath as R  import Network.URI @@ -51,12 +52,12 @@ 		let (keyname, file) = separate (== ' ') s 		if not (null keyname) && not (null file) 			then do-				file' <- liftIO $ relPathCwdToFile file+				file' <- liftIO $ relPathCwdToFile (toRawFilePath file) 				return $ Right (file', keyOpt keyname) 			else return $ 				Left "Expected pairs of key and filename" 	go (si, (file, key)) = -		let ai = mkActionItem (key, toRawFilePath file)+		let ai = mkActionItem (key, file) 		in starting "fromkey" ai si $ 			perform key file @@ -67,9 +68,11 @@ 		inbackend <- inAnnex key 		unless inbackend $ giveup $ 			"key ("++ keyname ++") is not present in backend (use --force to override this sanity check)"-	let ai = mkActionItem (key, toRawFilePath file)+	let ai = mkActionItem (key, file') 	starting "fromkey" ai si $-		perform key file+		perform key file'+  where+	file' = toRawFilePath file  -- From user input to a Key. -- User can input either a serialized key, or an url.@@ -86,15 +89,15 @@ 		Just k -> k 		Nothing -> giveup $ "bad key/url " ++ s -perform :: Key -> FilePath -> CommandPerform-perform key file = lookupKeyNotHidden (toRawFilePath file) >>= \case-	Nothing -> ifM (liftIO $ doesFileExist file)+perform :: Key -> RawFilePath -> CommandPerform+perform key file = lookupKeyNotHidden file >>= \case+	Nothing -> ifM (liftIO $ doesFileExist (fromRawFilePath file)) 		( hasothercontent 		, do 			link <- calcRepo $ gitAnnexLink file key 			createWorkTreeDirectory (parentDir file)-			liftIO $ createSymbolicLink link file-			Annex.Queue.addCommand "add" [Param "--"] [file]+			liftIO $ R.createSymbolicLink link file+			Annex.Queue.addCommand "add" [Param "--"] [fromRawFilePath file] 			next $ return True 		) 	Just k@@ -102,5 +105,5 @@ 		| otherwise -> hasothercontent   where 	hasothercontent = do-		warning $ file ++ " already exists with different content"+		warning $ fromRawFilePath file ++ " already exists with different content" 		next $ return False
Command/Fsck.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Command.Fsck where @@ -42,6 +43,7 @@ import qualified Data.Set as S import qualified Data.Map as M import Data.Either+import qualified System.FilePath.ByteString as P  cmd :: Command cmd = withGlobalOptions [jobsOption, jsonOptions, annexedMatchingOptions] $@@ -115,7 +117,7 @@ start from inc si file key = Backend.getBackend (fromRawFilePath file) key >>= \case 	Nothing -> stop 	Just backend -> do-		numcopies <- getFileNumCopies (fromRawFilePath file)+		numcopies <- getFileNumCopies file 		case from of 			Nothing -> go $ perform key file backend numcopies 			Just r -> go $ performRemote key afile backend numcopies r@@ -177,11 +179,11 @@ 		pid <- liftIO getPID 		t <- fromRepo gitAnnexTmpObjectDir 		createAnnexDirectory t-		let tmp = t </> "fsck" ++ show pid ++ "." ++ fromRawFilePath (keyFile key)-		let cleanup = liftIO $ catchIO (removeFile tmp) (const noop)+		let tmp = t P.</> "fsck" <> toRawFilePath (show pid) <> "." <> keyFile key+		let cleanup = liftIO $ catchIO (R.removeLink tmp) (const noop) 		cleanup 		cleanup `after` a tmp-	getfile tmp = ifM (checkDiskSpace (Just (takeDirectory tmp)) key 0 True)+	getfile tmp = ifM (checkDiskSpace (Just (P.takeDirectory tmp)) key 0 True) 		( ifM (getcheap tmp) 			( return (Just True) 			, ifM (Annex.getState Annex.fast)@@ -191,10 +193,10 @@ 			) 		, return (Just False) 		)-	getfile' tmp = Remote.retrieveKeyFile remote key (AssociatedFile Nothing) tmp dummymeter+	getfile' tmp = Remote.retrieveKeyFile remote key (AssociatedFile Nothing) (fromRawFilePath tmp) dummymeter 	dummymeter _ = noop 	getcheap tmp = case Remote.retrieveKeyFileCheap remote of-		Just a -> isRight <$> tryNonAsync (a key afile tmp)+		Just a -> isRight <$> tryNonAsync (a key afile (fromRawFilePath tmp)) 		Nothing -> return False  startKey :: Maybe Remote -> Incremental -> (SeekInput, Key, ActionItem) -> NumCopies -> CommandStart@@ -222,16 +224,16 @@ {- Checks that symlinks points correctly to the annexed content. -} fixLink :: Key -> RawFilePath -> Annex Bool fixLink key file = do-	want <- calcRepo $ gitAnnexLink (fromRawFilePath file) key+	want <- calcRepo $ gitAnnexLink file key 	have <- getAnnexLinkTarget file 	maybe noop (go want) have 	return True   where 	go want have-		| want /= fromRawFilePath (fromInternalGitPath have) = do+		| want /= fromInternalGitPath have = do 			showNote "fixing link"-			createWorkTreeDirectory (parentDir (fromRawFilePath file))-			liftIO $ removeFile (fromRawFilePath file)+			createWorkTreeDirectory (parentDir file)+			liftIO $ R.removeLink file 			addAnnexLink want file 		| otherwise = noop @@ -239,9 +241,9 @@  - in this repository only. -} verifyLocationLog :: Key -> KeyStatus -> ActionItem -> Annex Bool verifyLocationLog key keystatus ai = do-	obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)+	obj <- calcRepo (gitAnnexLocation key) 	present <- if isKeyUnlockedThin keystatus-		then liftIO (doesFileExist obj)+		then liftIO (doesFileExist (fromRawFilePath obj)) 		else inAnnex key 	u <- getUUID 	@@ -253,8 +255,8 @@ 			KeyLockedThin -> thawContent obj 			_ -> freezeContent obj 		unlessM (isContentWritePermOk obj) $-			warning $ "** Unable to set correct write mode for " ++ obj ++ " ; perhaps you don't own that file"-	whenM (liftIO $ doesDirectoryExist $ parentDir obj) $+			warning $ "** Unable to set correct write mode for " ++ fromRawFilePath obj ++ " ; perhaps you don't own that file"+	whenM (liftIO $ R.doesPathExist $ parentDir obj) $ 		freezeContentDir obj  	{- Warn when annex.securehashesonly is set and content using an @@ -263,7 +265,7 @@ 	 - config was set. -} 	whenM (pure present <&&> (not <$> Backend.isCryptographicallySecure key)) $ 		whenM (annexSecureHashesOnly <$> Annex.getGitConfig) $-			warning $ "** Despite annex.securehashesonly being set, " ++ obj ++ " has content present in the annex using an insecure " ++ decodeBS (formatKeyVariety (fromKey keyVariety key)) ++ " key"+			warning $ "** Despite annex.securehashesonly being set, " ++ fromRawFilePath obj ++ " has content present in the annex using an insecure " ++ decodeBS (formatKeyVariety (fromKey keyVariety key)) ++ " key"  	verifyLocationLog' key ai present u (logChange key u) @@ -344,13 +346,14 @@ 		Just k | k == key -> whenM (inAnnex key) $ do 			showNote "fixing worktree content" 			replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do+				let tmp' = toRawFilePath tmp 				mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 				ifM (annexThin <$> Annex.getGitConfig)-					( void $ linkFromAnnex key tmp mode+					( void $ linkFromAnnex key tmp' mode 					, do-						obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)-						void $ checkedCopyFile key obj tmp mode-						thawContent tmp+						obj <- calcRepo (gitAnnexLocation key)+						void $ checkedCopyFile key obj tmp' mode+						thawContent tmp' 					) 			Database.Keys.storeInodeCaches key [file] 		_ -> return ()@@ -366,19 +369,19 @@ checkKeySize key _ ai = do 	file <- calcRepo $ gitAnnexLocation key 	ifM (liftIO $ R.doesPathExist file)-		( checkKeySizeOr badContent key (fromRawFilePath file) ai+		( checkKeySizeOr badContent key file ai 		, return True 		) -withLocalCopy :: Maybe FilePath -> (FilePath -> Annex Bool) -> Annex Bool+withLocalCopy :: Maybe RawFilePath -> (RawFilePath -> Annex Bool) -> Annex Bool withLocalCopy Nothing _ = return True withLocalCopy (Just localcopy) f = f localcopy -checkKeySizeRemote :: Key -> Remote -> ActionItem -> FilePath -> Annex Bool+checkKeySizeRemote :: Key -> Remote -> ActionItem -> RawFilePath -> Annex Bool checkKeySizeRemote key remote ai localcopy = 	checkKeySizeOr (badContentRemote remote localcopy) key localcopy ai -checkKeySizeOr :: (Key -> Annex String) -> Key -> FilePath -> ActionItem -> Annex Bool+checkKeySizeOr :: (Key -> Annex String) -> Key -> RawFilePath -> ActionItem -> Annex Bool checkKeySizeOr bad key file ai = case fromKey keySize key of 	Nothing -> return True 	Just size -> do@@ -436,25 +439,25 @@ 	content <- calcRepo (gitAnnexLocation key) 	ifM (pure (isKeyUnlockedThin keystatus) <&&> (not <$> isUnmodified key content)) 		( nocheck-		, checkBackendOr badContent backend key (fromRawFilePath content) ai+		, checkBackendOr badContent backend key content ai 		)   where 	nocheck = return True  	ai = mkActionItem (key, afile) -checkBackendRemote :: Backend -> Key -> Remote -> ActionItem -> FilePath -> Annex Bool+checkBackendRemote :: Backend -> Key -> Remote -> ActionItem -> RawFilePath -> Annex Bool checkBackendRemote backend key remote ai localcopy = 	checkBackendOr (badContentRemote remote localcopy) backend key localcopy ai -checkBackendOr :: (Key -> Annex String) -> Backend -> Key -> FilePath -> ActionItem -> Annex Bool+checkBackendOr :: (Key -> Annex String) -> Backend -> Key -> RawFilePath -> ActionItem -> Annex Bool checkBackendOr bad backend key file ai = 	checkBackendOr' bad backend key file ai (return True)  -- The postcheck action is run after the content is verified, -- in order to detect situations where the file is changed while being -- verified.-checkBackendOr' :: (Key -> Annex String) -> Backend -> Key -> FilePath -> ActionItem -> Annex Bool -> Annex Bool+checkBackendOr' :: (Key -> Annex String) -> Backend -> Key -> RawFilePath -> ActionItem -> Annex Bool -> Annex Bool checkBackendOr' bad backend key file ai postcheck = 	case Types.Backend.verifyKeyContent backend of 		Nothing -> return True@@ -529,19 +532,20 @@  - symlink to a file in the remote). To avoid any further data loss,  - that temp file is moved to the bad content directory unless   - the local annex has a copy of the content. -}-badContentRemote :: Remote -> FilePath -> Key -> Annex String+badContentRemote :: Remote -> RawFilePath -> Key -> Annex String badContentRemote remote localcopy key = do 	bad <- fromRepo gitAnnexBadDir-	let destbad = bad </> fromRawFilePath (keyFile key)-	movedbad <- ifM (inAnnex key <||> liftIO (doesFileExist destbad))+	let destbad = bad P.</> keyFile key+	let destbad' = fromRawFilePath destbad+	movedbad <- ifM (inAnnex key <||> liftIO (doesFileExist destbad')) 		( return False 		, do 			createAnnexDirectory (parentDir destbad) 			liftIO $ catchDefaultIO False $-				ifM (isSymbolicLink <$> getSymbolicLinkStatus localcopy)-					( copyFileExternal CopyTimeStamps localcopy destbad+				ifM (isSymbolicLink <$> R.getSymbolicLinkStatus localcopy)+					( copyFileExternal CopyTimeStamps (fromRawFilePath localcopy) destbad' 					, do-						moveFile localcopy destbad+						moveFile (fromRawFilePath localcopy) destbad' 						return True 					) 		)@@ -551,7 +555,7 @@ 		Remote.logStatus remote key InfoMissing 	return $ case (movedbad, dropped) of 		(True, Right ()) -> "moved from " ++ Remote.name remote ++-			" to " ++ destbad+			" to " ++ fromRawFilePath destbad 		(False, Right ()) -> "dropped from " ++ Remote.name remote 		(_, Left e) -> "failed to drop from" ++ Remote.name remote ++ ": " ++ show e @@ -584,10 +588,10 @@ recordStartTime u = do 	f <- fromRepo (gitAnnexFsckState u) 	createAnnexDirectory $ parentDir f-	liftIO $ nukeFile f-	liftIO $ withFile f WriteMode $ \h -> do+	liftIO $ removeWhenExistsWith R.removeLink f+	liftIO $ withFile (fromRawFilePath f) WriteMode $ \h -> do #ifndef mingw32_HOST_OS-		t <- modificationTime <$> getFileStatus f+		t <- modificationTime <$> R.getFileStatus f #else 		t <- getPOSIXTime #endif@@ -598,16 +602,17 @@ 	showTime = show  resetStartTime :: UUID -> Annex ()-resetStartTime u = liftIO . nukeFile =<< fromRepo (gitAnnexFsckState u)+resetStartTime u = liftIO . removeWhenExistsWith R.removeLink+	=<< fromRepo (gitAnnexFsckState u)  {- Gets the incremental fsck start time. -} getStartTime :: UUID -> Annex (Maybe EpochTime) getStartTime u = do 	f <- fromRepo (gitAnnexFsckState u) 	liftIO $ catchDefaultIO Nothing $ do-		timestamp <- modificationTime <$> getFileStatus f+		timestamp <- modificationTime <$> R.getFileStatus f 		let fromstatus = Just (realToFrac timestamp)-		fromfile <- parsePOSIXTime <$> readFile f+		fromfile <- parsePOSIXTime <$> readFile (fromRawFilePath f) 		return $ if matchingtimestamp fromfile fromstatus 			then Just timestamp 			else Nothing
Command/FuzzTest.hs view
@@ -174,10 +174,11 @@  runFuzzAction :: FuzzAction -> Annex () runFuzzAction (FuzzAdd (FuzzFile f)) = do-	createWorkTreeDirectory (parentDir f)+	createWorkTreeDirectory (parentDir (toRawFilePath f)) 	n <- liftIO (getStdRandom random :: IO Int) 	liftIO $ writeFile f $ show n ++ "\n"-runFuzzAction (FuzzDelete (FuzzFile f)) = liftIO $ nukeFile f+runFuzzAction (FuzzDelete (FuzzFile f)) = liftIO $+	removeWhenExistsWith removeLink f runFuzzAction (FuzzMove (FuzzFile src) (FuzzFile dest)) = liftIO $ 	rename src dest runFuzzAction (FuzzDeleteDir (FuzzDir d)) = liftIO $@@ -208,7 +209,7 @@ 			case md of 				Nothing -> genFuzzAction 				Just d -> do-					newd <- liftIO $ newDir (parentDir $ toFilePath d)+					newd <- liftIO $ newDir (parentDir $ toRawFilePath $ toFilePath d) 					maybe genFuzzAction (return . FuzzMoveDir d) newd 		FuzzDeleteDir _ -> do 			d <- liftIO existingDir@@ -260,13 +261,13 @@ 			, go (n - 1) 			) -newDir :: FilePath -> IO (Maybe FuzzDir)+newDir :: RawFilePath -> IO (Maybe FuzzDir) newDir parent = go (100 :: Int)   where 	go 0 = return Nothing 	go n = do 		(FuzzDir d) <- genFuzzDir-		ifM (doesnotexist (parent </> d))+		ifM (doesnotexist (fromRawFilePath parent </> d)) 			( return $ Just $ FuzzDir d 			, go (n - 1) 			)
Command/Get.hs view
@@ -60,7 +60,7 @@ 	afile = AssociatedFile (Just file) 	ai = mkActionItem (key, afile) 	expensivecheck-		| autoMode o = numCopiesCheck (fromRawFilePath file) key (<)+		| autoMode o = numCopiesCheck file key (<) 			<||> wantGet False (Just key) afile 		| otherwise = return True @@ -118,5 +118,6 @@ 		download (Remote.uuid r) key afile stdRetry 			(\p -> do 				showAction $ "from " ++ Remote.name r-				Remote.verifiedAction (Remote.retrieveKeyFile r key afile dest p)+				Remote.verifiedAction $+					Remote.retrieveKeyFile r key afile (fromRawFilePath dest) p 			) witness
Command/Import.hs view
@@ -34,6 +34,7 @@ import Git.Types import Types.Import import Utility.Metered+import qualified Utility.RawFilePath as R  import Control.Concurrent.STM @@ -118,10 +119,11 @@  seek :: ImportOptions -> CommandSeek seek o@(LocalImportOptions {}) = startConcurrency commandStages $ do-	repopath <- liftIO . absPath . fromRawFilePath =<< fromRepo Git.repoPath-	inrepops <- liftIO $ filter (dirContains repopath) <$> mapM absPath (importFiles o)+	repopath <- liftIO . absPath =<< fromRepo Git.repoPath+	inrepops <- liftIO $ filter (dirContains repopath)+		<$> mapM (absPath . toRawFilePath) (importFiles o) 	unless (null inrepops) $ do-		giveup $ "cannot import files from inside the working tree (use git annex add instead): " ++ unwords inrepops+		giveup $ "cannot import files from inside the working tree (use git annex add instead): " ++ unwords (map fromRawFilePath inrepops) 	largematcher <- largeFilesMatcher 	addunlockedmatcher <- addUnlockedMatcher 	(commandAction . startLocal o addunlockedmatcher largematcher (duplicateMode o))@@ -136,23 +138,21 @@ 		(importToSubDir o) 	seekRemote r (importToBranch o) subdir (importContent o) (checkGitIgnoreOption o) -startLocal :: ImportOptions -> AddUnlockedMatcher -> GetFileMatcher -> DuplicateMode -> (FilePath, FilePath) -> CommandStart+startLocal :: ImportOptions -> AddUnlockedMatcher -> GetFileMatcher -> DuplicateMode -> (RawFilePath, RawFilePath) -> CommandStart startLocal o addunlockedmatcher largematcher mode (srcfile, destfile) =-	ifM (liftIO $ isRegularFile <$> getSymbolicLinkStatus srcfile)+	ifM (liftIO $ isRegularFile <$> R.getSymbolicLinkStatus srcfile) 		( starting "import" ai si pickaction 		, stop 		)   where- 	ai = ActionItemWorkTreeFile destfile'+ 	ai = ActionItemWorkTreeFile destfile 	si = SeekInput [] -	destfile' = toRawFilePath destfile- 	deletedup k = do 		showNote $ "duplicate of " ++ serializeKey k 		verifyExisting k destfile 			( do-				liftIO $ removeFile srcfile+				liftIO $ R.removeLink srcfile 				next $ return True 			, do 				warning "Could not verify that the content is still present in the annex; not removing from the import location."@@ -165,35 +165,35 @@ 		ignored <- checkIgnored (checkGitIgnoreOption o) destfile 		if ignored 			then do-				warning $ "not importing " ++ destfile ++ " which is .gitignored (use --no-check-gitignore to override)"+				warning $ "not importing " ++ fromRawFilePath destfile ++ " which is .gitignored (use --no-check-gitignore to override)" 				stop 			else do-				existing <- liftIO (catchMaybeIO $ getSymbolicLinkStatus destfile)+				existing <- liftIO (catchMaybeIO $ R.getSymbolicLinkStatus destfile) 				case existing of 					Nothing -> importfilechecked ld k 					Just s 						| isDirectory s -> notoverwriting "(is a directory)" 						| isSymbolicLink s -> ifM (Annex.getState Annex.force) 							( do-								liftIO $ nukeFile destfile+								liftIO $ removeWhenExistsWith R.removeLink destfile 								importfilechecked ld k 							, notoverwriting "(is a symlink)" 							) 						| otherwise -> ifM (Annex.getState Annex.force) 							( do-								liftIO $ nukeFile destfile+								liftIO $ removeWhenExistsWith R.removeLink destfile 								importfilechecked ld k 							, notoverwriting "(use --force to override, or a duplication option such as --deduplicate to clean up)" 							) 	checkdestdir cont = do 		let destdir = parentDir destfile-		existing <- liftIO (catchMaybeIO $ getSymbolicLinkStatus destdir)+		existing <- liftIO (catchMaybeIO $ R.getSymbolicLinkStatus destdir) 		case existing of 			Nothing -> cont 			Just s 				| isDirectory s -> cont 				| otherwise -> do-					warning $ "not importing " ++ destfile ++ " because " ++ destdir ++ " is not a directory"+					warning $ "not importing " ++ fromRawFilePath destfile ++ " because " ++ fromRawFilePath destdir ++ " is not a directory" 					stop  	importfilechecked ld k = do@@ -201,13 +201,17 @@ 		-- The dest file is what will be ingested. 		createWorkTreeDirectory (parentDir destfile) 		liftIO $ if mode == Duplicate || mode == SkipDuplicates-			then void $ copyFileExternal CopyAllMetaData srcfile destfile-			else moveFile srcfile destfile+			then void $ copyFileExternal CopyAllMetaData +				(fromRawFilePath srcfile)+				(fromRawFilePath destfile)+			else moveFile +				(fromRawFilePath srcfile)+				(fromRawFilePath destfile) 		-- Get the inode cache of the dest file. It should be 		-- weakly the same as the originally locked down file's 		-- inode cache. (Since the file may have been copied, 		-- its inodes may not be the same.)-		newcache <- withTSDelta $ liftIO . genInodeCache destfile'+		newcache <- withTSDelta $ liftIO . genInodeCache destfile 		let unchanged = case (newcache, inodeCache (keySource ld)) of 			(_, Nothing) -> True 			(Just newc, Just c) | compareWeak c newc -> True@@ -218,8 +222,8 @@ 		-- is what will be ingested. 		let ld' = ld 			{ keySource = KeySource-				{ keyFilename = destfile'-				, contentLocation = destfile'+				{ keyFilename = destfile+				, contentLocation = destfile 				, inodeCache = newcache 				} 			}@@ -228,15 +232,15 @@ 				>>= maybe 					stop 					(\addedk -> next $ Command.Add.cleanup addedk True)-			, next $ Command.Add.addSmall (checkGitIgnoreOption o) destfile'+			, next $ Command.Add.addSmall (checkGitIgnoreOption o) destfile 			) 	notoverwriting why = do-		warning $ "not overwriting existing " ++ destfile ++ " " ++ why+		warning $ "not overwriting existing " ++ fromRawFilePath destfile ++ " " ++ why 		stop 	lockdown a = do 		let mi = MatchingFile $ FileInfo-			{ contentFile = Just (toRawFilePath srcfile)-			, matchFile = toRawFilePath destfile+			{ contentFile = Just srcfile+			, matchFile = destfile 			} 		lockingfile <- not <$> addUnlocked addunlockedmatcher mi 		-- Minimal lock down with no hard linking so nothing@@ -245,7 +249,7 @@ 			{ lockingFile = lockingfile 			, hardlinkFileTmpDir = Nothing 			}-		v <- lockDown cfg srcfile+		v <- lockDown cfg (fromRawFilePath srcfile) 		case v of 			Just ld -> do 				backend <- chooseBackend destfile@@ -270,7 +274,7 @@ 		_ -> importfile ld k 	skipbecause s = showNote (s ++ "; skipping") >> next (return True) -verifyExisting :: Key -> FilePath -> (CommandPerform, CommandPerform) -> CommandPerform+verifyExisting :: Key -> RawFilePath -> (CommandPerform, CommandPerform) -> CommandPerform verifyExisting key destfile (yes, no) = do 	-- Look up the numcopies setting for the file that it would be 	-- imported to, if it were imported.
Command/ImportFeed.hs view
@@ -22,6 +22,7 @@ import qualified Data.Text as T import System.Log.Logger import Control.Concurrent.Async+import qualified System.FilePath.ByteString as P  import Command import qualified Annex@@ -188,13 +189,14 @@ performDownload addunlockedmatcher opts cache todownload = case location todownload of 	Enclosure url -> checkknown url $ 		rundownload url (takeWhile (/= '?') $ takeExtension url) $ \f -> do+			let f' = fromRawFilePath f 			r <- Remote.claimingUrl url 			if Remote.uuid r == webUUID || rawOption (downloadOptions opts) 				then do 					let dlopts = (downloadOptions opts) 						-- force using the filename 						-- chosen here-						{ fileOption = Just f+						{ fileOption = Just f' 						-- don't use youtube-dl 						, rawOption = True 						}@@ -218,7 +220,8 @@ 								downloadRemoteFile addunlockedmatcher r (downloadOptions opts) url f sz 						Right (UrlMulti l) -> do 							kl <- forM l $ \(url', sz, subf) ->-								downloadRemoteFile addunlockedmatcher r (downloadOptions opts) url' (f </> sanitizeFilePath subf) sz+								let dest = f P.</> toRawFilePath (sanitizeFilePath subf)+								in downloadRemoteFile addunlockedmatcher r (downloadOptions opts) url' dest sz 							return $ Just $ if all isJust kl 								then catMaybes kl 								else []@@ -257,7 +260,7 @@ 			Nothing -> return True 			Just f -> do 				showStartOther "addurl" (Just url) (SeekInput [])-				getter f >>= \case+				getter (toRawFilePath f) >>= \case 					Just ks 						-- Download problem. 						| null ks -> do@@ -307,7 +310,7 @@ 		| rawOption (downloadOptions opts) = downloadlink 		| otherwise = do 			r <- withTmpWorkDir mediakey $ \workdir -> do-				dl <- youtubeDl linkurl workdir nullMeterUpdate+				dl <- youtubeDl linkurl (fromRawFilePath workdir) nullMeterUpdate 				case dl of 					Right (Just mediafile) -> do 						let ext = case takeExtension mediafile of@@ -315,7 +318,7 @@ 							s -> s 						ok <- rundownload linkurl ext $ \f -> 							checkCanAdd (downloadOptions opts) f $ \canadd -> do-								addWorkTree canadd addunlockedmatcher webUUID mediaurl f mediakey (Just mediafile)+								addWorkTree canadd addunlockedmatcher webUUID mediaurl f mediakey (Just (toRawFilePath mediafile)) 								return (Just [mediakey]) 						return (Just ok) 					-- youtude-dl didn't support it, so@@ -454,9 +457,10 @@  - least 23 hours. -} checkFeedBroken :: URLString -> Annex Bool checkFeedBroken url = checkFeedBroken' url =<< feedState url-checkFeedBroken' :: URLString -> FilePath -> Annex Bool+checkFeedBroken' :: URLString -> RawFilePath -> Annex Bool checkFeedBroken' url f = do-	prev <- maybe Nothing readish <$> liftIO (catchMaybeIO $ readFile f)+	prev <- maybe Nothing readish+		<$> liftIO (catchMaybeIO $ readFile (fromRawFilePath f)) 	now <- liftIO getCurrentTime 	case prev of 		Nothing -> do@@ -471,7 +475,9 @@ 			return broken  clearFeedProblem :: URLString -> Annex ()-clearFeedProblem url = void $ liftIO . tryIO . removeFile =<< feedState url+clearFeedProblem url =+	void $ liftIO . tryIO . removeFile . fromRawFilePath+		=<< feedState url -feedState :: URLString -> Annex FilePath+feedState :: URLString -> Annex RawFilePath feedState url = fromRepo $ gitAnnexFeedState $ fromUrl url Nothing
Command/Info.hs view
@@ -12,6 +12,7 @@ import "mtl" Control.Monad.State.Strict import qualified Data.Map.Strict as M import qualified Data.Vector as V+import qualified System.FilePath.ByteString as P import Data.Ord import qualified Data.Semigroup as Sem import Prelude@@ -152,9 +153,9 @@ 				case v' of 					Right u -> uuidInfo o u si 					Left _ -> do-						relp <- liftIO $ relPathCwdToFile p-						ifAnnexed (toRawFilePath relp)-							(fileInfo o relp si)+						relp <- liftIO $ relPathCwdToFile (toRawFilePath p)+						ifAnnexed relp+							(fileInfo o (fromRawFilePath relp) si) 							(treeishInfo o p si) 	)   where@@ -435,7 +436,7 @@   where 	desc = "transfers in progress" 	line uuidmap t i = unwords-		[ formatDirection (transferDirection t) ++ "ing"+		[ fromRawFilePath (formatDirection (transferDirection t)) ++ "ing" 		, fromRawFilePath $ actionItemDesc $ mkActionItem 			(transferKey t, associatedFile i) 		, if transferDirection t == Upload then "to" else "from"@@ -579,7 +580,7 @@ 					then return (numcopiesstats, repodata) 					else do 						locs <- Remote.keyLocations key-						nc <- updateNumCopiesStats (fromRawFilePath file) numcopiesstats locs+						nc <- updateNumCopiesStats file numcopiesstats locs 						return (nc, updateRepoData key locs repodata) 				return $! (presentdata', referenceddata', numcopiesstats', repodata') 			, return vs@@ -643,7 +644,7 @@ 		M.fromList $ zip locs (map update locs) 	update loc = addKey key (fromMaybe emptyKeyInfo $ M.lookup loc m) -updateNumCopiesStats :: FilePath -> NumCopiesStats -> [UUID] -> Annex NumCopiesStats+updateNumCopiesStats :: RawFilePath -> NumCopiesStats -> [UUID] -> Annex NumCopiesStats updateNumCopiesStats file (NumCopiesStats m) locs = do 	have <- trustExclude UnTrusted locs 	!variance <- Variance <$> numCopiesCheck' file (-) have@@ -663,7 +664,7 @@ 			"+ " ++ show (unknownSizeKeys d) ++ 			" unknown size" -staleSize :: String -> (Git.Repo -> FilePath) -> Stat+staleSize :: String -> (Git.Repo -> RawFilePath) -> Stat staleSize label dirspec = go =<< lift (dirKeys dirspec)   where 	go [] = nostat@@ -675,8 +676,8 @@ 			return $ sizer storageUnits False size 	keysizes keys = do 		dir <- lift $ fromRepo dirspec-		liftIO $ forM keys $ \k -> catchDefaultIO 0 $-			getFileSize (dir </> fromRawFilePath (keyFile k))+		liftIO $ forM keys $ \k -> +			catchDefaultIO 0 $ getFileSize (dir P.</> keyFile k)  aside :: String -> String aside s = " (" ++ s ++ ")"
Command/Inprogress.hs view
@@ -55,7 +55,7 @@  start' :: Key -> CommandStart start' k = startingCustomOutput k $ do-	tmpf <- fromRepo $ gitAnnexTmpObjectLocation k+	tmpf <- fromRawFilePath <$> fromRepo (gitAnnexTmpObjectLocation k) 	whenM (liftIO $ doesFileExist tmpf) $ 		liftIO $ putStrLn tmpf 	next $ return True
Command/Lock.hs view
@@ -60,26 +60,25 @@ perform :: RawFilePath -> Key -> CommandPerform perform file key = do 	lockdown =<< calcRepo (gitAnnexLocation key)-	addLink (CheckGitIgnore False) (fromRawFilePath file) key+	addLink (CheckGitIgnore False) file key 		=<< withTSDelta (liftIO . genInodeCache file) 	next $ cleanup file key   where 	lockdown obj = do 		ifM (isUnmodified key obj) 			( breakhardlink obj-			, repopulate (fromRawFilePath obj)+			, repopulate obj 			) 		whenM (liftIO $ R.doesPathExist obj) $-			freezeContent $ fromRawFilePath obj+			freezeContent obj  	-- It's ok if the file is hard linked to obj, but if some other 	-- associated file is, we need to break that link to lock down obj. 	breakhardlink obj = whenM (catchBoolIO $ (> 1) . linkCount <$> liftIO (R.getFileStatus obj)) $ do 		mfc <- withTSDelta (liftIO . genInodeCache file) 		unlessM (sameInodeCache obj (maybeToList mfc)) $ do-			let obj' = fromRawFilePath obj-			modifyContent obj' $ replaceGitAnnexDirFile obj' $ \tmp -> do-				unlessM (checkedCopyFile key obj' tmp Nothing) $+			modifyContent obj $ replaceGitAnnexDirFile (fromRawFilePath obj) $ \tmp -> do+				unlessM (checkedCopyFile key obj (toRawFilePath tmp) Nothing) $ 					giveup "unable to lock file" 			Database.Keys.storeInodeCaches key [obj] @@ -89,10 +88,10 @@ 		fs <- map (`fromTopFilePath` g) 			<$> Database.Keys.getAssociatedFiles key 		mfile <- firstM (isUnmodified key) fs-		liftIO $ nukeFile obj+		liftIO $ removeWhenExistsWith R.removeLink obj 		case mfile of 			Just unmodified ->-				unlessM (checkedCopyFile key (fromRawFilePath unmodified) obj Nothing)+				unlessM (checkedCopyFile key unmodified obj Nothing) 					lostcontent 			Nothing -> lostcontent 
Command/Log.hs view
@@ -12,6 +12,7 @@ import Data.Char import Data.Time.Clock.POSIX import Data.Time+import qualified System.FilePath.ByteString as P  import Command import Logs@@ -207,10 +208,10 @@ getKeyLog :: Key -> [CommandParam] -> Annex ([RefChange], IO Bool) getKeyLog key os = do 	top <- fromRepo Git.repoPath-	p <- liftIO $ relPathCwdToFile $ fromRawFilePath top+	p <- liftIO $ relPathCwdToFile top 	config <- Annex.getGitConfig-	let logfile = p </> fromRawFilePath (locationLogFile config key)-	getGitLog [logfile] (Param "--remove-empty" : os)+	let logfile = p P.</> locationLogFile config key+	getGitLog [fromRawFilePath logfile] (Param "--remove-empty" : os)  {- Streams the git log for all git-annex branch changes. -} getAllLog :: [CommandParam] -> Annex ([RefChange], IO Bool)
Command/Map.hs view
@@ -178,8 +178,7 @@ 	| Git.repoIsUrl reference = return $ Git.Construct.localToUrl reference r 	| Git.repoIsUrl r = return r 	| otherwise = liftIO $ do-		r' <- Git.Construct.fromAbsPath-			=<< absPath (fromRawFilePath (Git.repoPath r))+		r' <- Git.Construct.fromAbsPath =<< absPath (Git.repoPath r) 		r'' <- safely $ flip Annex.eval Annex.gitRepo =<< Annex.new r' 		return (fromMaybe r' r'') 
Command/MetaData.hs view
@@ -165,8 +165,8 @@ 			(Just k, _) -> return $ 				Right (Right k, m) 			(Nothing, Just f) -> do-				f' <- liftIO $ relPathCwdToFile f-				return $ Right (Left (toRawFilePath f'), m)+				f' <- liftIO $ relPathCwdToFile (toRawFilePath f)+				return $ Right (Left f', m) 			(Nothing, Nothing) -> return $  				Left "JSON input is missing either file or key" 
Command/Migrate.hs view
@@ -44,7 +44,7 @@ 		Just oldbackend -> do 			exists <- inAnnex key 			newbackend <- maybe defaultBackend return -				=<< chooseBackend (fromRawFilePath file)+				=<< chooseBackend file 			if (newbackend /= oldbackend || upgradableKey oldbackend key || forced) && exists 				then starting "migrate" (mkActionItem (key, file)) si $ 					perform file key oldbackend newbackend
Command/Mirror.hs view
@@ -88,4 +88,4 @@   where 	getnumcopies = case afile of 		AssociatedFile Nothing -> getNumCopies-		AssociatedFile (Just af) -> getFileNumCopies (fromRawFilePath af)+		AssociatedFile (Just af) -> getFileNumCopies af
Command/Move.hs view
@@ -151,7 +151,7 @@ 					when fastcheck $ 						warning "This could have failed because --fast is enabled." 					stop-		Right True -> logMove srcuuid destuuid False key $ \deststartedwithcopy ->+		Right True -> logMove srcuuid destuuid True key $ \deststartedwithcopy -> 			finish deststartedwithcopy $ 				unlessM (expectedPresent dest key) $ 					Remote.logStatus dest key InfoPresent@@ -226,7 +226,7 @@ 	get = notifyTransfer Download afile $  		download (Remote.uuid src) key afile stdRetry $ \p -> 			getViaTmp (Remote.retrievalSecurityPolicy src) (RemoteVerify src) key $ \t ->-				Remote.verifiedAction $ Remote.retrieveKeyFile src key afile t p+				Remote.verifiedAction $ Remote.retrieveKeyFile src key afile (fromRawFilePath t) p 	 	dispatch _ _ False = stop -- failed 	dispatch RemoveNever _ True = next $ return True -- copy complete@@ -363,7 +363,7 @@ 	go logf 		-- Only need to check log when there is a copy. 		| deststartedwithcopy = do-			wasnocopy <- checkLogFile logf gitAnnexMoveLock+			wasnocopy <- checkLogFile (fromRawFilePath logf) gitAnnexMoveLock 				(== logline) 			if wasnocopy 				then go' False
Command/Multicast.hs view
@@ -83,8 +83,8 @@ 	(s, ok) <- case k of 		KeyContainer s -> liftIO $ genkey (Param s) 		KeyFile f -> do-			createAnnexDirectory (takeDirectory f)-			liftIO $ nukeFile f+			createAnnexDirectory (toRawFilePath (takeDirectory f))+			liftIO $ removeWhenExistsWith removeLink f 			liftIO $ protectedOutput $ genkey (File f) 	case (ok, parseFingerprint s) of 		(False, _) -> giveup $ "uftp_keymgt failed: " ++ s@@ -176,8 +176,8 @@ 	(callback, environ, statush) <- liftIO multicastCallbackEnv 	tmpobjdir <- fromRepo gitAnnexTmpObjectDir 	createAnnexDirectory tmpobjdir-	withTmpDirIn tmpobjdir "multicast" $ \tmpdir -> withAuthList $ \authlist -> do-		abstmpdir <- liftIO $ absPath tmpdir+	withTmpDirIn (fromRawFilePath tmpobjdir) "multicast" $ \tmpdir -> withAuthList $ \authlist -> do+		abstmpdir <- liftIO $ absPath (toRawFilePath tmpdir) 		abscallback <- liftIO $ searchPath callback 		let ps = 			-- Avoid it running as a daemon.@@ -190,7 +190,7 @@ 			, Param "-S", Param authlist 			-- Receive files into tmpdir 			-- (it needs an absolute path)-			, Param "-D", File abstmpdir+			, Param "-D", File (fromRawFilePath abstmpdir) 			-- Run callback after each file received 			-- (it needs an absolute path) 			, Param "-s", Param (fromMaybe callback abscallback)@@ -210,11 +210,11 @@ 	case deserializeKey (takeFileName f) of 		Nothing -> do 			warning $ "Received a file " ++ f ++ " that is not a git-annex key. Deleting this file."-			liftIO $ nukeFile f+			liftIO $ removeWhenExistsWith removeLink f 		Just k -> void $ 			getViaTmpFromDisk RetrievalVerifiableKeysSecure AlwaysVerify k $ \dest -> unVerified $ 				liftIO $ catchBoolIO $ do-					rename f dest+					rename f (fromRawFilePath dest) 					return True  -- Under Windows, uftp uses key containers, which are not files on the
Command/P2P.hs view
@@ -220,11 +220,11 @@ 	-- to read them. So, set up a temp directory that only 	-- we can read. 	withTmpDir "pair" $ \tmp -> do-		liftIO $ void $ tryIO $ modifyFileMode tmp $ +		liftIO $ void $ tryIO $ modifyFileMode (toRawFilePath tmp) $  			removeModes otherGroupModes 		let sendf = tmp </> "send" 		let recvf = tmp </> "recv"-		liftIO $ writeFileProtected sendf $+		liftIO $ writeFileProtected (toRawFilePath sendf) $ 			serializePairData ourpairdata  		observer <- liftIO Wormhole.mkCodeObserver@@ -256,7 +256,7 @@ 			Wormhole.sendFile sendf observer wormholeparams 				`concurrently` 			Wormhole.receiveFile recvf producer wormholeparams-		liftIO $ nukeFile sendf+		liftIO $ removeWhenExistsWith removeLink sendf 		if sendres /= True 			then return SendFailed 			else if recvres /= True
Command/ReKey.hs view
@@ -47,8 +47,8 @@ 			Nothing -> return $ Left "bad key" 			Just k -> do 				let f = reverse rf-				f' <- liftIO $ relPathCwdToFile f-				return $ Right (toRawFilePath f', k)+				f' <- liftIO $ relPathCwdToFile (toRawFilePath f)+				return $ Right (f', k)  seek :: ReKeyOptions -> CommandSeek seek o = case batchOption o of@@ -91,27 +91,28 @@ 	 - unlocked file, which would leave the new key unlocked 	 - and vulnerable to corruption. -} 	( getViaTmpFromDisk RetrievalAllKeysSecure DefaultVerify newkey $ \tmp -> unVerified $ do-		oldobj <- fromRawFilePath <$> calcRepo (gitAnnexLocation oldkey)+		oldobj <- calcRepo (gitAnnexLocation oldkey) 		isJust <$> linkOrCopy' (return True) newkey oldobj tmp Nothing 	, do 	 	{- The file being rekeyed is itself an unlocked file; if 		 - it's hard linked to the old key, that link must be broken. -}-		oldobj <- fromRawFilePath <$> calcRepo (gitAnnexLocation oldkey)+		oldobj <- calcRepo (gitAnnexLocation oldkey) 		v <- tryNonAsync $ do 			st <- liftIO $ R.getFileStatus file 			when (linkCount st > 1) $ do 				freezeContent oldobj 				replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do-					unlessM (checkedCopyFile oldkey oldobj tmp Nothing) $+					let tmp' = toRawFilePath tmp+					unlessM (checkedCopyFile oldkey oldobj tmp' Nothing) $ 						error "can't lock old key"-					thawContent tmp+					thawContent tmp' 		ic <- withTSDelta (liftIO . genInodeCache file) 		case v of 			Left e -> do 				warning (show e) 				return False 			Right () -> do-				r <- linkToAnnex newkey (fromRawFilePath file) ic+				r <- linkToAnnex newkey file ic 				return $ case r of 					LinkAnnexFailed -> False 					LinkAnnexOk -> True@@ -124,7 +125,7 @@ 		( do 			-- Update symlink to use the new key. 			liftIO $ removeFile (fromRawFilePath file)-			addLink (CheckGitIgnore False) (fromRawFilePath file) newkey Nothing+			addLink (CheckGitIgnore False) file newkey Nothing 		, do 			mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 			liftIO $ whenM (isJust <$> isPointerFile file) $
Command/RecvKey.hs view
@@ -45,4 +45,4 @@ 	go tmp = unVerified $ do 		opts <- filterRsyncSafeOptions . maybe [] words 			<$> getField "RsyncOptions"-		liftIO $ rsyncServerReceive (map Param opts) tmp+		liftIO $ rsyncServerReceive (map Param opts) (fromRawFilePath tmp)
Command/Reinject.hs view
@@ -43,11 +43,13 @@ startSrcDest :: [FilePath] -> CommandStart startSrcDest ps@(src:dest:[]) 	| src == dest = stop-	| otherwise = notAnnexed src $ ifAnnexed (toRawFilePath dest) go stop+	| otherwise = notAnnexed src' $+		ifAnnexed (toRawFilePath dest) go stop   where+	src' = toRawFilePath src 	go key = starting "reinject" ai si $-		ifM (verifyKeyContent RetrievalAllKeysSecure DefaultVerify UnVerified key src)-			( perform src key+		ifM (verifyKeyContent RetrievalAllKeysSecure DefaultVerify UnVerified key src')+			( perform src' key 			, giveup $ src ++ " does not have expected content of " ++ dest 			) 	ai = ActionItemOther (Just src)@@ -55,31 +57,31 @@ startSrcDest _ = giveup "specify a src file and a dest file"  startKnown :: FilePath -> CommandStart-startKnown src = notAnnexed src $+startKnown src = notAnnexed src' $ 	starting "reinject" ai si $ do 		(key, _) <- genKey ks nullMeterUpdate Nothing 		ifM (isKnownKey key)-			( perform src key+			( perform src' key 			, do 				warning "Not known content; skipping" 				next $ return True 			)   where-	ks = KeySource src' src' Nothing 	src' = toRawFilePath src+	ks = KeySource src' src' Nothing 	ai = ActionItemOther (Just src) 	si = SeekInput [src] -notAnnexed :: FilePath -> CommandStart -> CommandStart+notAnnexed :: RawFilePath -> CommandStart -> CommandStart notAnnexed src a =  	ifM (fromRepo Git.repoIsLocalBare) 		( a-		, ifAnnexed (toRawFilePath src)-			(giveup $ "cannot used annexed file as src: " ++ src)+		, ifAnnexed src+			(giveup $ "cannot used annexed file as src: " ++ fromRawFilePath src) 			a 		) -perform :: FilePath -> Key -> CommandPerform+perform :: RawFilePath -> Key -> CommandPerform perform src key = ifM move 	( next $ cleanup key 	, error "failed"
Command/Repair.hs view
@@ -14,6 +14,7 @@ import qualified Git.Ref import Git.Types import Annex.Version+import qualified Utility.RawFilePath as R  cmd :: Command cmd = noCommit $ dontCheck repoExists $@@ -75,7 +76,7 @@ 		Annex.Branch.forceCommit "committing index after git repository repair" 		liftIO $ putStrLn "Successfully recovered the git-annex branch using .git/annex/index" 	nukeindex = do-		inRepo $ nukeFile . gitAnnexIndex+		inRepo $ removeWhenExistsWith R.removeLink . gitAnnexIndex 		liftIO $ putStrLn "Had to delete the .git/annex/index file as it was corrupt." 	missingbranch = liftIO $ putStrLn "Since the git-annex branch is not up-to-date anymore. It would be a very good idea to run: git annex fsck --fast" 
Command/RmUrl.hs view
@@ -41,7 +41,8 @@ 		| null ru || null rf -> return $ Left "Expected: \"file url\"" 		| otherwise -> do 			let f = reverse rf-			f' <- liftIO $ relPathCwdToFile f+			f' <- liftIO $ fromRawFilePath+				<$> relPathCwdToFile (toRawFilePath f) 			return $ Right (f', reverse ru)  start :: (SeekInput, (FilePath, URLString)) -> CommandStart
Command/SetKey.hs view
@@ -21,7 +21,7 @@  start :: [String] -> CommandStart start ps@(keyname:file:[]) = starting "setkey" ai si $-	perform file (keyOpt keyname)+	perform (toRawFilePath file) (keyOpt keyname)   where 	ai = ActionItemOther (Just file) 	si = SeekInput ps@@ -30,7 +30,7 @@ keyOpt :: String -> Key keyOpt = fromMaybe (giveup "bad key") . deserializeKey -perform :: FilePath -> Key -> CommandPerform+perform :: RawFilePath -> Key -> CommandPerform perform file key = do 	-- the file might be on a different filesystem, so moveFile is used 	-- rather than simply calling moveAnnex; disk space is also@@ -38,7 +38,7 @@ 	ok <- getViaTmp RetrievalAllKeysSecure DefaultVerify key $ \dest -> unVerified $ 		if dest /= file 			then liftIO $ catchBoolIO $ do-				moveFile file dest+				moveFile (fromRawFilePath file) (fromRawFilePath dest) 				return True 		else return True 	if ok
Command/Smudge.hs view
@@ -54,7 +54,7 @@  seek :: SmudgeOptions -> CommandSeek seek (SmudgeOptions f False) = commandAction (smudge f)-seek (SmudgeOptions f True) = commandAction (clean f)+seek (SmudgeOptions f True) = commandAction (clean (toRawFilePath f)) seek UpdateOption = commandAction update  -- Smudge filter is fed git file content, and if it's a pointer to an@@ -83,7 +83,7 @@ -- Clean filter is fed file content on stdin, decides if a file -- should be stored in the annex, and outputs a pointer to its -- injested content if so. Otherwise, the original content.-clean :: FilePath -> CommandStart+clean :: RawFilePath -> CommandStart clean file = do 	b <- liftIO $ L.hGetContents stdin 	ifM fileoutsiderepo@@ -98,10 +98,11 @@   where 	go b = case parseLinkTargetOrPointerLazy b of 		Just k -> do-			getMoveRaceRecovery k (toRawFilePath file)-			liftIO $ L.hPut stdout b+			addingExistingLink file k $ do+				getMoveRaceRecovery k file+				liftIO $ L.hPut stdout b 		Nothing -> do-			let fileref = Git.Ref.fileRef (toRawFilePath file)+			let fileref = Git.Ref.fileRef file 			indexmeta <- catObjectMetaData fileref 			go' b indexmeta =<< catKey' fileref indexmeta 	go' b indexmeta oldkey = ifM (shouldAnnex file indexmeta oldkey)@@ -120,7 +121,7 @@ 			-- annexed and is unmodified. 			case oldkey of 				Nothing -> doingest oldkey-				Just ko -> ifM (isUnmodifiedCheap ko (toRawFilePath file))+				Just ko -> ifM (isUnmodifiedCheap ko file) 					( liftIO $ emitPointer ko 					, doingest oldkey 					)@@ -141,7 +142,7 @@ 		liftIO . emitPointer 			=<< postingest 			=<< (\ld -> ingest' oldbackend nullMeterUpdate ld Nothing norestage)-			=<< lockDown cfg file+			=<< lockDown cfg (fromRawFilePath file)  	postingest (Just k, _) = do 		logStatus k InfoPresent@@ -156,8 +157,7 @@ 	-- git diff can run the clean filter on files outside the 	-- repository; can't annex those 	fileoutsiderepo = do-	        repopath <- liftIO . absPath . fromRawFilePath-			=<< fromRepo Git.repoPath+	        repopath <- liftIO . absPath =<< fromRepo Git.repoPath 		filepath <- liftIO $ absPath file 		return $ not $ dirContains repopath filepath @@ -175,7 +175,7 @@ -- annexed content before, annex it. This handles cases such as renaming an -- unlocked annexed file followed by git add, which the user naturally -- expects to behave the same as git mv.-shouldAnnex :: FilePath -> Maybe (Sha, FileSize, ObjectType) -> Maybe Key -> Annex Bool+shouldAnnex :: RawFilePath -> Maybe (Sha, FileSize, ObjectType) -> Maybe Key -> Annex Bool shouldAnnex file indexmeta moldkey = ifM (annexGitAddToAnnex <$> Annex.getGitConfig) 	( checkunchangedgitfile $ checkmatcher checkheuristics 	, checkunchangedgitfile checkheuristics@@ -196,7 +196,7 @@ 		Just _ -> return True 		Nothing -> checkknowninode -	checkknowninode = withTSDelta (liftIO . genInodeCache (toRawFilePath file)) >>= \case+	checkknowninode = withTSDelta (liftIO . genInodeCache file) >>= \case 		Nothing -> pure False 		Just ic -> Database.Keys.isInodeKnown ic =<< sentinalStatus 
Command/Status.hs view
@@ -61,6 +61,6 @@ displayStatus s = do 	let c = statusChar s 	absf <- fromRepo $ fromTopFilePath (statusFile s)-	f <- liftIO $ relPathCwdToFile $ fromRawFilePath absf+	f <- liftIO $ fromRawFilePath <$> relPathCwdToFile absf 	unlessM (showFullJSON $ JSONChunk [("status", [c]), ("file", f)]) $ 		liftIO $ putStrLn $ [c] ++ " " ++ f
Command/Sync.hs view
@@ -191,7 +191,7 @@ 		<*> pure (pushOption v) 		<*> pure (contentOption v) 		<*> pure (noContentOption v)-		<*> liftIO (mapM absPath (contentOfOption v))+		<*> liftIO (mapM (fromRawFilePath <$$> absPath . toRawFilePath) (contentOfOption v)) 		<*> pure (cleanupOption v) 		<*> pure (keyOptions v) 		<*> pure (resolveMergeOverride v)
Command/TestRemote.hs view
@@ -251,7 +251,7 @@ 	, check "fsck downloaded object" fsck 	, check "retrieveKeyFile resume from 33%" $ \r k -> do 		loc <- fromRawFilePath <$> Annex.calcRepo (gitAnnexLocation k)-		tmp <- prepTmp k+		tmp <- fromRawFilePath <$> prepTmp k 		partial <- liftIO $ bracket (openBinaryFile loc ReadMode) hClose $ \h -> do 			sz <- hFileSize h 			L.hGet h $ fromInteger $ sz `div` 3@@ -260,14 +260,14 @@ 		get r k 	, check "fsck downloaded object" fsck 	, check "retrieveKeyFile resume from 0" $ \r k -> do-		tmp <- prepTmp k+		tmp <- fromRawFilePath <$> prepTmp k 		liftIO $ writeFile tmp "" 		lockContentForRemoval k noop removeAnnex 		get r k 	, check "fsck downloaded object" fsck 	, check "retrieveKeyFile resume from end" $ \r k -> do 		loc <- fromRawFilePath <$> Annex.calcRepo (gitAnnexLocation k)-		tmp <- prepTmp k+		tmp <- fromRawFilePath <$> prepTmp k 		void $ liftIO $ copyFileExternal CopyAllMetaData loc tmp 		lockContentForRemoval k noop removeAnnex 		get r k@@ -293,9 +293,9 @@ 		Nothing -> return True 		Just b -> case Types.Backend.verifyKeyContent b of 			Nothing -> return True-			Just verifier -> verifier k (serializeKey k)+			Just verifier -> verifier k (serializeKey' k) 	get r k = getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) k $ \dest ->-		tryNonAsync (Remote.retrieveKeyFile r k (AssociatedFile Nothing) dest nullMeterUpdate) >>= \case+		tryNonAsync (Remote.retrieveKeyFile r k (AssociatedFile Nothing) (fromRawFilePath dest) nullMeterUpdate) >>= \case 			Right v -> return (True, v) 			Left _ -> return (False, UnVerified) 	store r k = Remote.storeKey r k (AssociatedFile Nothing) nullMeterUpdate@@ -352,7 +352,7 @@ 		liftIO $ hClose h 		tryNonAsync (Remote.retrieveExport ea k testexportlocation tmp nullMeterUpdate) >>= \case 			Left _ -> return False-			Right () -> verifyKeyContent RetrievalAllKeysSecure AlwaysVerify UnVerified k tmp+			Right () -> verifyKeyContent RetrievalAllKeysSecure AlwaysVerify UnVerified k (toRawFilePath tmp) 	checkpresentexport ea k = Remote.checkPresentExport ea k testexportlocation 	removeexport ea k = Remote.removeExport ea k testexportlocation 	removeexportdirectory ea = case Remote.removeExportDirectory ea of@@ -369,14 +369,14 @@ 		Remote.checkPresent r k 	, check (== Right False) "retrieveKeyFile" $ \r k -> 		getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) k $ \dest ->-			tryNonAsync (Remote.retrieveKeyFile r k (AssociatedFile Nothing) dest nullMeterUpdate) >>= \case+			tryNonAsync (Remote.retrieveKeyFile r k (AssociatedFile Nothing) (fromRawFilePath dest) nullMeterUpdate) >>= \case 				Right v -> return (True, v) 				Left _ -> return (False, UnVerified) 	, check (== Right False) "retrieveKeyFileCheap" $ \r k -> case Remote.retrieveKeyFileCheap r of 		Nothing -> return False 		Just a -> getViaTmp (Remote.retrievalSecurityPolicy r) (RemoteVerify r) k $ \dest ->  			unVerified $ isRight-				<$> tryNonAsync (a k (AssociatedFile Nothing) dest)+				<$> tryNonAsync (a k (AssociatedFile Nothing) (fromRawFilePath dest)) 	]   where 	check checkval desc a = testCase desc $ @@ -436,7 +436,7 @@ 	k <- case Types.Backend.genKey Backend.Hash.testKeyBackend of 		Just a -> a ks nullMeterUpdate 		Nothing -> giveup "failed to generate random key (backend problem)"-	_ <- moveAnnex k f+	_ <- moveAnnex k (toRawFilePath f) 	return k  getReadonlyKey :: Remote -> FilePath -> Annex Key
Command/TransferInfo.hs view
@@ -11,9 +11,10 @@ import Annex.Content import Types.Transfer import Logs.Transfer-import qualified CmdLine.GitAnnexShell.Fields as Fields import Utility.Metered import Utility.SimpleProtocol+import qualified CmdLine.GitAnnexShell.Fields as Fields+import qualified Utility.RawFilePath as R  cmd :: Command cmd = noCommit $ @@ -58,7 +59,7 @@ 					bytes <- readUpdate 					maybe (error "transferinfo protocol error") 						(update . toBytesProcessed) bytes-				, tryIO $ removeFile tfile+				, tryIO $ R.removeLink tfile 				, exitSuccess 				] 	stop
Command/TransferKey.hs view
@@ -64,7 +64,7 @@ fromPerform key file remote = go Upload file $ 	download (uuid remote) key file stdRetry $ \p -> 		getViaTmp (retrievalSecurityPolicy remote) (RemoteVerify remote) key $ \t ->-			tryNonAsync (Remote.retrieveKeyFile remote key file t p) >>= \case+			tryNonAsync (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p) >>= \case 				Right v -> return (True, v)	 				Left e -> do 					warning (show e)
Command/TransferKeys.hs view
@@ -48,7 +48,7 @@ 		| otherwise = notifyTransfer direction file $ 			download (Remote.uuid remote) key file stdRetry $ \p -> 				getViaTmp (Remote.retrievalSecurityPolicy remote) (RemoteVerify remote) key $ \t -> do-					r <- tryNonAsync (Remote.retrieveKeyFile remote key file t p) >>= \case+					r <- tryNonAsync (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p) >>= \case 						Left e -> do 							warning (show e) 							return (False, UnVerified)
Command/Unannex.hs view
@@ -14,6 +14,7 @@ import Utility.CopyFile import qualified Database.Keys import Git.FilePath+import qualified Utility.RawFilePath as R  cmd :: Command cmd = withGlobalOptions [annexedMatchingOptions] $@@ -54,7 +55,7 @@ cleanup :: RawFilePath -> Key -> CommandCleanup cleanup file key = do 	Database.Keys.removeAssociatedFile key =<< inRepo (toTopFilePath file)-	src <- fromRawFilePath <$> calcRepo (gitAnnexLocation key)+	src <- calcRepo (gitAnnexLocation key) 	ifM (Annex.getState Annex.fast) 		( do 			-- Only make a hard link if the annexed file does not@@ -62,19 +63,21 @@ 			-- This avoids unannexing (and uninit) ending up 			-- hard linking files together, which would be 			-- surprising.-			s <- liftIO $ getFileStatus src+			s <- liftIO $ R.getFileStatus src 			if linkCount s > 1 				then copyfrom src 				else hardlinkfrom src 		, copyfrom src 		)   where-	file' = fromRawFilePath file 	copyfrom src = -		thawContent file' `after` liftIO (copyFileExternal CopyAllMetaData src file')+		thawContent file `after` liftIO +			(copyFileExternal CopyAllMetaData+				(fromRawFilePath src)+				(fromRawFilePath file)) 	hardlinkfrom src = 		-- creating a hard link could fall; fall back to copying-		ifM (liftIO $ catchBoolIO $ createLink src file' >> return True)+		ifM (liftIO $ catchBoolIO $ R.createLink src file >> return True) 			( return True 			, copyfrom src 			)
Command/Undo.hs view
@@ -16,6 +16,7 @@ import qualified Git.Command as Git import qualified Git.Branch import qualified Command.Sync+import qualified Utility.RawFilePath as R  cmd :: Command cmd = notBareRepo $@@ -62,15 +63,15 @@ 	-- and then any adds. This order is necessary to handle eg, removing 	-- a directory and replacing it with a file. 	let (removals, adds) = partition (\di -> dstsha di `elem` nullShas) diff'-	let mkrel di = liftIO $ relPathCwdToFile $ fromRawFilePath $+	let mkrel di = liftIO $ relPathCwdToFile $ 		fromTopFilePath (file di) g  	forM_ removals $ \di -> do 		f <- mkrel di-		liftIO $ nukeFile f+		liftIO $ removeWhenExistsWith R.removeLink f  	forM_ adds $ \di -> do-		f <- mkrel di+		f <- fromRawFilePath <$> mkrel di 		inRepo $ Git.run [Param "checkout", Param "--", File f]  	next $ liftIO cleanup
Command/Uninit.hs view
@@ -31,8 +31,8 @@ 	b <- current_branch 	when (b == Annex.Branch.name) $ giveup $ 		"cannot uninit when the " ++ Git.fromRef b ++ " branch is checked out"-	top <- fromRawFilePath <$> fromRepo Git.repoPath-	currdir <- liftIO getCurrentDirectory+	top <- fromRepo Git.repoPath+	currdir <- liftIO R.getCurrentDirectory 	whenM ((/=) <$> liftIO (absPath top) <*> liftIO (absPath currdir)) $ 		giveup "can only run uninit from the top of the git repository"   where@@ -73,7 +73,7 @@ 		then liftIO $ removeDirectoryRecursive annexdir 		else giveup $ unlines 			[ "Not fully uninitialized"-			, "Some annexed data is still left in " ++ annexobjectdir+			, "Some annexed data is still left in " ++ fromRawFilePath annexobjectdir 			, "This may include deleted files, or old versions of modified files." 			, "" 			, "If you don't care about preserving the data, just delete the"@@ -108,7 +108,7 @@ prepareRemoveAnnexDir' :: FilePath -> IO () prepareRemoveAnnexDir' annexdir = 	dirTreeRecursiveSkipping (const False) annexdir -		>>= mapM_ (void . tryIO . allowWrite)+		>>= mapM_ (void . tryIO . allowWrite . toRawFilePath)  {- Keys that were moved out of the annex have a hard link still in the  - annex, with > 1 link count, and those can be removed.
Command/Unlock.hs view
@@ -50,7 +50,7 @@ 	replaceWorkTreeFile (fromRawFilePath dest) $ \tmp -> 		ifM (inAnnex key) 			( do-				r <- linkFromAnnex key tmp destmode+				r <- linkFromAnnex key (toRawFilePath tmp) destmode 				case r of 					LinkAnnexOk -> return () 					LinkAnnexNoop -> return ()
Command/Unused.hs view
@@ -108,7 +108,7 @@ 	l <- a 	let unusedlist = number c l 	unless (null l) $ showLongNote $ msg unusedlist-	updateUnusedLog file $ M.fromList unusedlist+	updateUnusedLog (toRawFilePath file) (M.fromList unusedlist) 	return $ c + length l  number :: Int -> [a] -> [(Int, a)]
Command/Vicfg.hs view
@@ -43,11 +43,12 @@ start :: CommandStart start = do 	f <- fromRepo gitAnnexTmpCfgFile+	let f' = fromRawFilePath f 	createAnnexDirectory $ parentDir f 	cfg <- getCfg 	descs <- uuidDescriptions-	liftIO $ writeFile f $ genCfg cfg descs-	vicfg cfg f+	liftIO $ writeFile f' $ genCfg cfg descs+	vicfg cfg f' 	stop  vicfg :: Cfg -> FilePath -> Annex ()@@ -57,7 +58,7 @@ 	unlessM (liftIO $ boolSystem "sh" [Param "-c", Param $ unwords [vi, shellEscape f]]) $ 		giveup $ vi ++ " exited nonzero; aborting" 	r <- parseCfg (defCfg curcfg) <$> liftIO (readFileStrict f)-	liftIO $ nukeFile f+	liftIO $ removeWhenExistsWith removeLink f 	case r of 		Left s -> do 			liftIO $ writeFile f s
Command/View.hs view
@@ -19,6 +19,8 @@ import Annex.View import Logs.View +import qualified System.FilePath.ByteString as P+ cmd :: Command cmd = notBareRepo $ 	command "view" SectionMetaData "enter a view branch"@@ -101,19 +103,19 @@ 		 - and this pollutes the view, so remove them. 		 - (However, emptry directories used by submodules are not 		 - removed.) -}-		top <- liftIO . absPath . fromRawFilePath =<< fromRepo Git.repoPath+		top <- liftIO . absPath =<< fromRepo Git.repoPath 		(l, cleanup) <- inRepo $-			LsFiles.notInRepoIncludingEmptyDirectories [] False-				[toRawFilePath top]+			LsFiles.notInRepoIncludingEmptyDirectories [] False [top] 		forM_ l (removeemptydir top) 		liftIO $ void cleanup 		unlessM (liftIO $ doesDirectoryExist here) $ do-			showLongNote (cwdmissing top)+			showLongNote (cwdmissing (fromRawFilePath top)) 	return ok   where 	removeemptydir top d = do 		p <- inRepo $ toTopFilePath d-		liftIO $ tryIO $ removeDirectory (top </> fromRawFilePath (getTopFilePath p))+		liftIO $ tryIO $ removeDirectory $+			fromRawFilePath $ (top P.</> getTopFilePath p) 	cwdmissing top = unlines 		[ "This view does not include the subdirectory you are currently in." 		, "Perhaps you should:  cd " ++ top
Command/WebApp.hs view
@@ -27,7 +27,7 @@ import qualified Git.Config import qualified Git.CurrentRepo import qualified Annex-import Config.Files+import Config.Files.AutoStart import Upgrade import Annex.Version import Utility.Android@@ -75,15 +75,15 @@ 		listenAddress' <- if isJust (listenAddress o) 			then pure (listenAddress o) 			else annexListen <$> Annex.getGitConfig-		ifM (checkpid <&&> checkshim f)+		ifM (checkpid <&&> checkshim (fromRawFilePath f)) 			( if isJust (listenAddress o) 				then giveup "The assistant is already running, so --listen cannot be used." 				else do-					url <- liftIO . readFile+					url <- liftIO . readFile . fromRawFilePath 						=<< fromRepo gitAnnexUrlFile 					liftIO $ if isJust listenAddress' 						then putStrLn url-						else liftIO $ openBrowser browser f url Nothing Nothing+						else liftIO $ openBrowser browser (fromRawFilePath f) url Nothing Nothing 			, do 				startDaemon True True Nothing cannotrun listenAddress' $ Just $  					\origout origerr url htmlshim ->@@ -93,7 +93,7 @@ 			) 	checkpid = do 		pidfile <- fromRepo gitAnnexPidFile-		liftIO $ isJust <$> checkDaemon pidfile+		liftIO $ isJust <$> checkDaemon (fromRawFilePath pidfile) 	checkshim f = liftIO $ doesFileExist f 	notinitialized = do 		g <- Annex.gitRepo@@ -105,8 +105,8 @@ notHome :: Annex Bool notHome = do 	g <- Annex.gitRepo-	d <- liftIO $ absPath (Git.repoLocation g)-	h <- liftIO $ absPath =<< myHomeDir+	d <- liftIO $ absPath (Git.repoPath g)+	h <- liftIO $ absPath . toRawFilePath =<< myHomeDir 	return (d /= h)  {- When run without a repo, start the first available listed repository in@@ -191,7 +191,7 @@  openBrowser :: Maybe FilePath -> FilePath -> String -> Maybe Handle -> Maybe Handle -> IO () openBrowser mcmd htmlshim realurl outh errh = do-	htmlshim' <- absPath htmlshim+	htmlshim' <- fromRawFilePath <$> absPath (toRawFilePath htmlshim) 	openBrowser' mcmd htmlshim' realurl outh errh  openBrowser' :: Maybe FilePath -> FilePath -> String -> Maybe Handle -> Maybe Handle -> IO ()
Common.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE PackageImports #-}- module Common (module X) where  import Control.Monad as X@@ -21,9 +19,12 @@ import Utility.Exception as X import Utility.DebugLocks as X import Utility.SafeCommand as X+import Utility.ShellEscape as X import Utility.Process as X import Utility.Path as X+import Utility.Path.AbsRel as X import Utility.Directory as X+import Utility.MoveFile as X import Utility.Monad as X import Utility.Data as X import Utility.Applicative as X
Config.hs view
@@ -85,7 +85,7 @@ setCrippledFileSystem b = 	setConfig (annexConfig "crippledfilesystem") (Git.Config.boolConfig b) -pidLockFile :: Annex (Maybe FilePath)+pidLockFile :: Annex (Maybe RawFilePath) #ifndef mingw32_HOST_OS pidLockFile = ifM (annexPidLock <$> Annex.getGitConfig) 	( Just <$> Annex.fromRepo gitAnnexPidLockFile
Config/Files.hs view
@@ -9,10 +9,11 @@  module Config.Files where -import Common-import Utility.Tmp import Utility.FreeDesktop+import Utility.Exception +import System.FilePath+ {- ~/.config/git-annex/file -} userConfigFile :: FilePath -> IO FilePath userConfigFile file = do@@ -21,40 +22,6 @@  autoStartFile :: IO FilePath autoStartFile = userConfigFile "autostart"--{- Returns anything listed in the autostart file (which may not exist). -}-readAutoStartFile :: IO [FilePath]-readAutoStartFile = do-	f <- autoStartFile-	filter valid . nub . map dropTrailingPathSeparator . lines-		<$> catchDefaultIO "" (readFile f)-  where-	-- Ignore any relative paths; some old buggy versions added eg "."-	valid = isAbsolute--modifyAutoStartFile :: ([FilePath] -> [FilePath]) -> IO ()-modifyAutoStartFile func = do-	dirs <- readAutoStartFile-	let dirs' = nubBy equalFilePath $ func dirs-	when (dirs' /= dirs) $ do-		f <- autoStartFile-		createDirectoryIfMissing True (parentDir f)-		viaTmp writeFile f $ unlines dirs'--{- Adds a directory to the autostart file. If the directory is already- - present, it's moved to the top, so it will be used as the default- - when opening the webapp. -}-addAutoStartFile :: FilePath -> IO ()-addAutoStartFile path = do-	path' <- absPath path-	modifyAutoStartFile $ (:) path'--{- Removes a directory from the autostart file. -}-removeAutoStartFile :: FilePath -> IO ()-removeAutoStartFile path = do-	path' <- absPath path-	modifyAutoStartFile $-		filter (not . equalFilePath path')  {- The path to git-annex is written here; which is useful when something  - has installed it to some awful non-PATH location. -}
+ Config/Files/AutoStart.hs view
@@ -0,0 +1,49 @@+{- git-annex autostart file+ -+ - Copyright 2012-2019 Joey Hess <id@joeyh.name>+ -+ - Licensed under the GNU AGPL version 3 or higher.+ -}++{-# OPTIONS_GHC -fno-warn-tabs #-}++module Config.Files.AutoStart where++import Common+import Config.Files+import Utility.Tmp++{- Returns anything listed in the autostart file (which may not exist). -}+readAutoStartFile :: IO [FilePath]+readAutoStartFile = do+	f <- autoStartFile+	filter valid . nub . map dropTrailingPathSeparator . lines+		<$> catchDefaultIO "" (readFile f)+  where+	-- Ignore any relative paths; some old buggy versions added eg "."+	valid = isAbsolute++modifyAutoStartFile :: ([FilePath] -> [FilePath]) -> IO ()+modifyAutoStartFile func = do+	dirs <- readAutoStartFile+	let dirs' = nubBy equalFilePath $ func dirs+	when (dirs' /= dirs) $ do+		f <- autoStartFile+		createDirectoryIfMissing True $+			fromRawFilePath (parentDir (toRawFilePath f))+		viaTmp writeFile f $ unlines dirs'++{- Adds a directory to the autostart file. If the directory is already+ - present, it's moved to the top, so it will be used as the default+ - when opening the webapp. -}+addAutoStartFile :: FilePath -> IO ()+addAutoStartFile path = do+	path' <- fromRawFilePath <$> absPath (toRawFilePath path)+	modifyAutoStartFile $ (:) path'++{- Removes a directory from the autostart file. -}+removeAutoStartFile :: FilePath -> IO ()+removeAutoStartFile path = do+	path' <- fromRawFilePath <$> absPath (toRawFilePath path)+	modifyAutoStartFile $+		filter (not . equalFilePath path')
Config/Smudge.hs view
@@ -15,7 +15,10 @@ import qualified Git.Command import Git.Types import Config+import Utility.Directory.Create +import qualified System.FilePath.ByteString as P+ configureSmudgeFilter :: Annex () configureSmudgeFilter = unlessM (fromRepo Git.repoIsLocalBare) $ do 	-- If this is run in a newly cloned repository, git may not have@@ -33,12 +36,12 @@ 	gf <- Annex.fromRepo Git.attributes 	lfs <- readattr lf 	gfs <- readattr gf-	gittop <- fromRawFilePath . Git.localGitDir <$> gitRepo+	gittop <- Git.localGitDir <$> gitRepo 	liftIO $ unless ("filter=annex" `isInfixOf` (lfs ++ gfs)) $ do-		createDirectoryUnder gittop (takeDirectory lf)-		writeFile lf (lfs ++ "\n" ++ unlines stdattr)+		createDirectoryUnder gittop (P.takeDirectory lf)+		writeFile (fromRawFilePath lf) (lfs ++ "\n" ++ unlines stdattr)   where-	readattr = liftIO . catchDefaultIO "" . readFileStrict+	readattr = liftIO . catchDefaultIO "" . readFileStrict . fromRawFilePath  stdattr :: [String] stdattr =@@ -51,7 +54,7 @@ -- git-annex does not commit that. deconfigureSmudgeFilter :: Annex () deconfigureSmudgeFilter = do-	lf <- Annex.fromRepo Git.attributesLocal+	lf <- fromRawFilePath <$> Annex.fromRepo Git.attributesLocal 	ls <- liftIO $ catchDefaultIO [] $ lines <$> readFileStrict lf 	liftIO $ writeFile lf $ unlines $ 		filter (\l -> l `notElem` stdattr && not (null l)) ls
Creds.hs view
@@ -36,6 +36,7 @@ import qualified Data.ByteString.Lazy.Char8 as L import qualified Data.ByteString.Char8 as S import qualified Data.Map as M+import qualified System.FilePath.ByteString as P import Utility.Base64  {- A CredPair can be stored in a file, or in the environment, or@@ -190,14 +191,14 @@ writeCreds creds file = do 	d <- fromRepo gitAnnexCredsDir 	createAnnexDirectory d-	liftIO $ writeFileProtected (d </> file) creds+	liftIO $ writeFileProtected (d P.</> toRawFilePath file) creds  readCreds :: FilePath -> Annex (Maybe Creds) readCreds f = liftIO . catchMaybeIO . readFileStrict =<< credsFile f  credsFile :: FilePath -> Annex FilePath credsFile basefile = do-	d <- fromRepo gitAnnexCredsDir+	d <- fromRawFilePath <$> fromRepo gitAnnexCredsDir 	return $ d </> basefile  encodeCredPair :: CredPair -> Creds@@ -210,9 +211,9 @@  removeCreds :: FilePath -> Annex () removeCreds file = do-	d <- fromRepo gitAnnexCredsDir+	d <- fromRawFilePath <$> fromRepo gitAnnexCredsDir 	let f = d </> file-	liftIO $ nukeFile f+	liftIO $ removeWhenExistsWith removeLink f  includeCredsInfo :: ParsedRemoteConfig -> CredPairStorage -> [(String, String)] -> Annex [(String, String)] includeCredsInfo pc@(ParsedRemoteConfig cm _) storage info = do
Database/Benchmark.hs view
@@ -25,12 +25,13 @@ import qualified Data.ByteString.Char8 as B8 import System.Random import Control.Concurrent+import qualified System.FilePath.ByteString as P #endif  benchmarkDbs :: CriterionMode -> Integer -> Annex () #ifdef WITH_BENCHMARK benchmarkDbs mode n = withTmpDirIn "." "benchmark" $ \tmpdir -> do-	db <- benchDb tmpdir n+	db <- benchDb (toRawFilePath tmpdir) n 	liftIO $ runMode mode 		[ bgroup "keys database" 			[ getAssociatedFilesHitBench db@@ -101,7 +102,7 @@  data BenchDb = BenchDb H.DbQueue Integer (MVar Integer) -benchDb :: FilePath -> Integer -> Annex BenchDb+benchDb :: RawFilePath -> Integer -> Annex BenchDb benchDb tmpdir num = do 	liftIO $ putStrLn $ "setting up database with " ++ show num ++ " items" 	initDb db SQL.createTables@@ -113,6 +114,6 @@ 	mv <- liftIO $ newMVar 1 	return (BenchDb h num mv)   where-	db = tmpdir </> show num </> "db"+	db = tmpdir P.</> toRawFilePath (show num </> "db")  #endif /* WITH_BENCHMARK */
Database/ContentIdentifier.hs view
@@ -10,6 +10,7 @@ {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts, EmptyDataDecls #-} {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE DataKinds, FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} #if MIN_VERSION_persistent_template(2,8,0) {-# LANGUAGE DerivingStrategies #-}@@ -47,9 +48,11 @@ import qualified Git.DiffTree as DiffTree import Logs import qualified Logs.ContentIdentifier as Log+import qualified Utility.RawFilePath as R  import Database.Persist.Sql hiding (Key) import Database.Persist.TH+import qualified System.FilePath.ByteString as P  data ContentIdentifierHandle = ContentIdentifierHandle H.DbQueue @@ -75,8 +78,8 @@ openDb :: Annex ContentIdentifierHandle openDb = do 	dbdir <- fromRepo gitAnnexContentIdentifierDbDir-	let db = dbdir </> "db"-	unlessM (liftIO $ doesFileExist db) $ do+	let db = dbdir P.</> "db"+	unlessM (liftIO $ R.doesPathExist db) $ do 		initDb db $ void $ 			runMigrationSilent migrateContentIdentifier 	h <- liftIO $ H.openDbQueue H.SingleWriter db "content_identifiers"
Database/Export.hs view
@@ -10,6 +10,7 @@ {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE DataKinds, FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} #if MIN_VERSION_persistent_template(2,8,0) {-# LANGUAGE DerivingStrategies #-}@@ -59,9 +60,11 @@ import Git.Sha import Git.FilePath import qualified Git.DiffTree+import qualified Utility.RawFilePath as R  import Database.Persist.Sql hiding (Key) import Database.Persist.TH+import qualified System.FilePath.ByteString as P  data ExportHandle = ExportHandle H.DbQueue UUID @@ -97,8 +100,8 @@ openDb :: UUID -> Annex ExportHandle openDb u = do 	dbdir <- fromRepo (gitAnnexExportDbDir u)-	let db = dbdir </> "db"-	unlessM (liftIO $ doesFileExist db) $ do+	let db = dbdir P.</> "db"+	unlessM (liftIO $ R.doesPathExist db) $ do 		initDb db $ void $ 			runMigrationSilent migrateExport 	h <- liftIO $ H.openDbQueue H.SingleWriter db "exported"
Database/Fsck.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE QuasiQuotes, TypeFamilies, TemplateHaskell #-} {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DataKinds, FlexibleInstances #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE UndecidableInstances #-} #if MIN_VERSION_persistent_template(2,8,0)@@ -33,10 +34,12 @@ import Utility.Exception import Annex.Common import Annex.LockFile+import qualified Utility.RawFilePath as R  import Database.Persist.Sql hiding (Key) import Database.Persist.TH import Data.Time.Clock+import qualified System.FilePath.ByteString as P  data FsckHandle = FsckHandle H.DbQueue UUID @@ -62,14 +65,14 @@ 	go = do 		removedb =<< fromRepo (gitAnnexFsckDbDir u) 		removedb =<< fromRepo (gitAnnexFsckDbDirOld u)-	removedb = liftIO . void . tryIO . removeDirectoryRecursive+	removedb = liftIO . void . tryIO . removeDirectoryRecursive . fromRawFilePath  {- Opens the database, creating it if it doesn't exist yet. -} openDb :: UUID -> Annex FsckHandle openDb u = do 	dbdir <- fromRepo (gitAnnexFsckDbDir u)-	let db = dbdir </> "db"-	unlessM (liftIO $ doesFileExist db) $ do+	let db = dbdir P.</> "db"+	unlessM (liftIO $ R.doesPathExist db) $ do 		initDb db $ void $ 			runMigrationSilent migrateFsck 	lockFileCached =<< fromRepo (gitAnnexFsckDbLock u)
Database/Handle.hs view
@@ -63,10 +63,10 @@  {- Opens the database, but does not perform any migrations. Only use  - once the database is known to exist and have the right tables. -}-openDb :: DbConcurrency -> FilePath -> TableName -> IO DbHandle+openDb :: DbConcurrency -> RawFilePath -> TableName -> IO DbHandle openDb dbconcurrency db tablename = do 	jobs <- newEmptyMVar-	worker <- async (workerThread (T.pack db) tablename jobs)+	worker <- async (workerThread (T.pack (fromRawFilePath db)) tablename jobs) 	 	-- work around https://github.com/yesodweb/persistent/issues/474 	liftIO $ fileEncoding stderr
Database/Init.hs view
@@ -5,15 +5,20 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Database.Init where  import Annex.Common import Annex.Perms import Utility.FileMode+import Utility.Directory.Create+import qualified Utility.RawFilePath as R  import Database.Persist.Sqlite-import qualified Data.Text as T import Lens.Micro+import qualified Data.Text as T+import qualified System.FilePath.ByteString as P  {- Ensures that the database is freshly initialized. Deletes any  - existing database. Pass the migration action for the database.@@ -23,24 +28,24 @@  - file causes Sqlite to always use the same permissions for additional  - files it writes later on  -}-initDb :: FilePath -> SqlPersistM () -> Annex ()+initDb :: P.RawFilePath -> SqlPersistM () -> Annex () initDb db migration = do-	let dbdir = takeDirectory db-	let tmpdbdir = dbdir ++ ".tmp"-	let tmpdb = tmpdbdir </> "db"-	let tdb = T.pack tmpdb-	top <- parentDir . fromRawFilePath <$> fromRepo gitAnnexDir+	let dbdir = P.takeDirectory db+	let tmpdbdir = dbdir <> ".tmp"+	let tmpdb = tmpdbdir P.</> "db"+	let tdb = T.pack (fromRawFilePath tmpdb)+	top <- parentDir <$> fromRepo gitAnnexDir 	liftIO $ do 		createDirectoryUnder top tmpdbdir 		runSqliteInfo (enableWAL tdb) migration 	setAnnexDirPerm tmpdbdir 	-- Work around sqlite bug that prevents it from honoring 	-- less restrictive umasks.-	liftIO $ setFileMode tmpdb =<< defaultFileMode+	liftIO $ R.setFileMode tmpdb =<< defaultFileMode 	setAnnexFilePerm tmpdb 	liftIO $ do-		void $ tryIO $ removeDirectoryRecursive dbdir-		rename tmpdbdir dbdir+		void $ tryIO $ removeDirectoryRecursive (fromRawFilePath dbdir)+		rename (fromRawFilePath tmpdbdir) (fromRawFilePath dbdir)  {- Make sure that the database uses WAL mode, to prevent readers  - from blocking writers, and prevent a writer from blocking readers.
Database/Keys.hs view
@@ -43,6 +43,7 @@ import Git.Command import Git.Types import Git.Index+import qualified Utility.RawFilePath as R  import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8@@ -114,8 +115,8 @@ openDb False DbUnavailable = return DbUnavailable openDb createdb _ = catchPermissionDenied permerr $ withExclusiveLock gitAnnexKeysDbLock $ do 	dbdir <- fromRepo gitAnnexKeysDb-	let db = dbdir </> "db"-	dbexists <- liftIO $ doesFileExist db+	let db = dbdir P.</> "db"+	dbexists <- liftIO $ R.doesPathExist db 	case (dbexists, createdb) of 		(True, _) -> open db 		(False, True) -> do@@ -214,8 +215,8 @@ reconcileStaged :: H.DbQueue -> Annex () reconcileStaged qh = do 	gitindex <- inRepo currentIndexFile-	indexcache <- fromRepo gitAnnexKeysDbIndexCache-	withTSDelta (liftIO . genInodeCache (toRawFilePath gitindex)) >>= \case+	indexcache <- fromRawFilePath <$> fromRepo gitAnnexKeysDbIndexCache+	withTSDelta (liftIO . genInodeCache gitindex) >>= \case 		Just cur ->  			liftIO (maybe Nothing readInodeCache <$> catchMaybeIO (readFile indexcache)) >>= \case 				Nothing -> go cur indexcache
Database/Keys/SQL.hs view
@@ -10,6 +10,7 @@ {-# LANGUAGE OverloadedStrings, GADTs, FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes, ScopedTypeVariables #-}+{-# LANGUAGE DataKinds, FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} #if MIN_VERSION_persistent_template(2,8,0) {-# LANGUAGE DerivingStrategies #-}
Database/Queue.hs view
@@ -19,6 +19,7 @@ ) where  import Utility.Monad+import Utility.RawFilePath import Database.Handle  import Database.Persist.Sqlite@@ -36,7 +37,7 @@ {- Opens the database queue, but does not perform any migrations. Only use  - if the database is known to exist and have the right tables; ie after  - running initDb. -}-openDbQueue :: DbConcurrency -> FilePath -> TableName -> IO DbQueue+openDbQueue :: DbConcurrency -> RawFilePath -> TableName -> IO DbQueue openDbQueue dbconcurrency db tablename = DQ 	<$> openDb dbconcurrency db tablename 	<*> (newMVar =<< emptyQueue)
Git.hs view
@@ -3,11 +3,12 @@  - This is written to be completely independant of git-annex and should be  - suitable for other uses.  -- - Copyright 2010-2012 Joey Hess <id@joeyh.name>+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}  module Git (@@ -37,10 +38,12 @@ 	relPath, ) where +import qualified Data.ByteString as B import Network.URI (uriPath, uriScheme, unEscapeString) #ifndef mingw32_HOST_OS import System.Posix.Files #endif+import qualified System.FilePath.ByteString as P  import Common import Git.Types@@ -130,14 +133,13 @@ 	| otherwise = action  {- Path to a repository's gitattributes file. -}-attributes :: Repo -> FilePath+attributes :: Repo -> RawFilePath attributes repo 	| repoIsLocalBare repo = attributesLocal repo-	| otherwise = fromRawFilePath (repoPath repo) </> ".gitattributes"+	| otherwise = repoPath repo P.</> ".gitattributes" -attributesLocal :: Repo -> FilePath-attributesLocal repo = fromRawFilePath (localGitDir repo)-	</> "info" </> "attributes"+attributesLocal :: Repo -> RawFilePath+attributesLocal repo = localGitDir repo P.</> "info" P.</> "attributes"  {- Path to a given hook script in a repository, only if the hook exists  - and is executable. -}@@ -159,13 +161,13 @@   where 	torel p = do 		p' <- relPathCwdToFile p-		return $ if null p' then "." else p'+		return $ if B.null p' then "." else p'  {- Adusts the path to a local Repo using the provided function. -}-adjustPath :: (FilePath -> IO FilePath) -> Repo -> IO Repo+adjustPath :: (RawFilePath -> IO RawFilePath) -> Repo -> IO Repo adjustPath f r@(Repo { location = l@(Local { gitdir = d, worktree = w }) }) = do-	d' <- f' d-	w' <- maybe (pure Nothing) (Just <$$> f') w+	d' <- f d+	w' <- maybe (pure Nothing) (Just <$$> f) w 	return $ r  		{ location = l  			{ gitdir = d'@@ -173,8 +175,7 @@ 			} 		}   where-	f' v = toRawFilePath <$> f (fromRawFilePath v) adjustPath f r@(Repo { location = LocalUnknown d }) = do-	d' <- toRawFilePath <$> f (fromRawFilePath d)+	d' <- f d 	return $ r { location = LocalUnknown d' } adjustPath _ r = pure r
Git/CheckAttr.hs view
@@ -1,6 +1,6 @@ {- git check-attr interface  -- - Copyright 2010-2012 Joey Hess <id@joeyh.name>+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -11,10 +11,12 @@ import Git import Git.Command import qualified Utility.CoProcess as CoProcess+import qualified Utility.RawFilePath as R  import System.IO.Error+import qualified Data.ByteString as B -type CheckAttrHandle = (CoProcess.CoProcessHandle, [Attr], String)+type CheckAttrHandle = (CoProcess.CoProcessHandle, [Attr], RawFilePath)  type Attr = String @@ -22,7 +24,7 @@  - values and returns a handle.  -} checkAttrStart :: [Attr] -> Repo -> IO CheckAttrHandle checkAttrStart attrs repo = do-	currdir <- getCurrentDirectory+	currdir <- R.getCurrentDirectory 	h <- gitCoProcessStart True params repo 	return (h, attrs, currdir)   where@@ -38,16 +40,16 @@  {- Gets an attribute of a file. When the attribute is not specified,  - returns "" -}-checkAttr :: CheckAttrHandle -> Attr -> FilePath -> IO String+checkAttr :: CheckAttrHandle -> Attr -> RawFilePath -> IO String checkAttr (h, attrs, currdir) want file = do 	pairs <- CoProcess.query h send (receive "") 	let vals = map snd $ filter (\(attr, _) -> attr == want) pairs 	case vals of 		["unspecified"] -> return "" 		[v] -> return v-		_ -> error $ "unable to determine " ++ want ++ " attribute of " ++ file+		_ -> error $ "unable to determine " ++ want ++ " attribute of " ++ fromRawFilePath file   where-	send to = hPutStr to $ file' ++ "\0"+	send to = B.hPutStr to $ file' `B.snoc` 0 	receive c from = do 		s <- hGetSomeString from 1024 		if null s
Git/CheckIgnore.hs view
@@ -18,6 +18,7 @@ import qualified Utility.CoProcess as CoProcess  import System.IO.Error+import qualified Data.ByteString as B  type CheckIgnoreHandle = CoProcess.CoProcessHandle @@ -51,11 +52,11 @@ checkIgnoreStop = void . tryIO . CoProcess.stop  {- Returns True if a file is ignored. -}-checkIgnored :: CheckIgnoreHandle -> FilePath -> IO Bool+checkIgnored :: CheckIgnoreHandle -> RawFilePath -> IO Bool checkIgnored h file = CoProcess.query h send (receive "")   where 	send to = do-		hPutStr to $ file ++ "\0"+		B.hPutStr to $ file `B.snoc` 0 		hFlush to 	receive c from = do 		s <- hGetSomeString from 1024
Git/Config.hs view
@@ -141,9 +141,9 @@ 		Nothing -> return l 		Just (ConfigValue d) -> do 			{- core.worktree is relative to the gitdir -}-			top <- absPath $ fromRawFilePath (gitdir l)-			let p = absPathFrom top (fromRawFilePath d)-			return $ l { worktree = Just (toRawFilePath p) }+			top <- absPath (gitdir l)+			let p = absPathFrom top d+			return $ l { worktree = Just p } 		Just NoConfigValue -> return l 	return $ r { location = l' } 
Git/Construct.hs view
@@ -5,6 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}  module Git.Construct (@@ -38,6 +39,9 @@ import qualified Git.Url as Url import Utility.UserInfo +import qualified Data.ByteString as B+import qualified System.FilePath.ByteString as P+ {- Finds the git repository used for the cwd, which may be in a parent  - directory. -} fromCwd :: IO (Maybe Repo)@@ -46,40 +50,40 @@ 	seekUp dir = do 		r <- checkForRepo dir 		case r of-			Nothing -> case upFrom dir of+			Nothing -> case upFrom (toRawFilePath dir) of 				Nothing -> return Nothing-				Just d -> seekUp d+				Just d -> seekUp (fromRawFilePath d) 			Just loc -> pure $ Just $ newFrom loc  {- Local Repo constructor, accepts a relative or absolute path. -}-fromPath :: FilePath -> IO Repo+fromPath :: RawFilePath -> IO Repo fromPath dir = fromAbsPath =<< absPath dir  {- Local Repo constructor, requires an absolute path to the repo be  - specified. -}-fromAbsPath :: FilePath -> IO Repo+fromAbsPath :: RawFilePath -> IO Repo fromAbsPath dir-	| absoluteGitPath (encodeBS dir) = hunt+	| absoluteGitPath dir = hunt 	| otherwise =-		error $ "internal error, " ++ dir ++ " is not absolute"+		error $ "internal error, " ++ show dir ++ " is not absolute"   where-	ret = pure . newFrom . LocalUnknown . toRawFilePath-	canondir = dropTrailingPathSeparator dir+	ret = pure . newFrom . LocalUnknown+	canondir = P.dropTrailingPathSeparator dir 	{- When dir == "foo/.git", git looks for "foo/.git/.git", 	 - and failing that, uses "foo" as the repository. -} 	hunt-		| (pathSeparator:".git") `isSuffixOf` canondir =-			ifM (doesDirectoryExist $ dir </> ".git")+		| (P.pathSeparator `B.cons` ".git") `B.isSuffixOf` canondir =+			ifM (doesDirectoryExist $ fromRawFilePath dir </> ".git") 				( ret dir-				, ret (takeDirectory canondir)+				, ret (P.takeDirectory canondir) 				)-		| otherwise = ifM (doesDirectoryExist dir)+		| otherwise = ifM (doesDirectoryExist (fromRawFilePath dir)) 			( checkGitDirFile dir >>= maybe (ret dir) (pure . newFrom) 			-- git falls back to dir.git when dir doesn't 			-- exist, as long as dir didn't end with a 			-- path separator 			, if dir == canondir-				then ret (dir ++ ".git")+				then ret (dir <> ".git") 				else ret dir 			) @@ -95,7 +99,8 @@  fromUrlStrict :: String -> IO Repo fromUrlStrict url-	| "file://" `isPrefixOf` url = fromAbsPath $ unEscapeString $ uriPath u+	| "file://" `isPrefixOf` url = fromAbsPath $ toRawFilePath $+		unEscapeString $ uriPath u 	| otherwise = pure $ newFrom $ Url u   where 	u = fromMaybe bad $ parseURI url@@ -129,7 +134,8 @@ 	filterconfig f = filter f $ M.toList $ config repo 	filterkeys f = filterconfig (\(k,_) -> f k) 	remotepairs = filterkeys isRemoteKey-	construct (k,v) = remoteNamedFromKey k (fromRemoteLocation (fromConfigValue v) repo)+	construct (k,v) = remoteNamedFromKey k $+		fromRemoteLocation (fromConfigValue v) repo  {- Sets the name of a remote when constructing the Repo to represent it. -} remoteNamed :: String -> IO Repo -> IO Repo@@ -155,18 +161,18 @@ fromRemotePath :: FilePath -> Repo -> IO Repo fromRemotePath dir repo = do 	dir' <- expandTilde dir-	fromPath $ fromRawFilePath (repoPath repo) </> dir'+	fromPath $ repoPath repo P.</> toRawFilePath dir'  {- Git remotes can have a directory that is specified relative  - to the user's home directory, or that contains tilde expansions.  - This converts such a directory to an absolute path.  - Note that it has to run on the system where the remote is.  -}-repoAbsPath :: FilePath -> IO FilePath+repoAbsPath :: RawFilePath -> IO RawFilePath repoAbsPath d = do-	d' <- expandTilde d+	d' <- expandTilde (fromRawFilePath d) 	h <- myHomeDir-	return $ h </> d'+	return $ toRawFilePath $ h </> d'  expandTilde :: FilePath -> IO FilePath #ifdef mingw32_HOST_OS@@ -199,7 +205,7 @@ checkForRepo :: FilePath -> IO (Maybe RepoLocation) checkForRepo dir =  	check isRepo $-		check (checkGitDirFile dir) $+		check (checkGitDirFile (toRawFilePath dir)) $ 			check isBareRepo $ 				return Nothing   where@@ -221,10 +227,10 @@ 	gitSignature file = doesFileExist $ dir </> file  -- Check for a .git file.-checkGitDirFile :: FilePath -> IO (Maybe RepoLocation)+checkGitDirFile :: RawFilePath -> IO (Maybe RepoLocation) checkGitDirFile dir = adjustGitDirFile' $ Local -	{ gitdir = toRawFilePath (dir </> ".git")-	, worktree = Just (toRawFilePath dir)+	{ gitdir = dir P.</> ".git"+	, worktree = Just dir 	}  -- git-submodule, git-worktree, and --separate-git-dir@@ -236,14 +242,16 @@  adjustGitDirFile' :: RepoLocation -> IO (Maybe RepoLocation) adjustGitDirFile' loc = do-	let gd = fromRawFilePath (gitdir loc)-	c <- firstLine <$> catchDefaultIO "" (readFile gd)+	let gd = gitdir loc+	c <- firstLine <$> catchDefaultIO "" (readFile (fromRawFilePath gd)) 	if gitdirprefix `isPrefixOf` c 		then do-			top <- takeDirectory <$> absPath gd+			top <- fromRawFilePath . P.takeDirectory <$> absPath gd 			return $ Just $ loc-				{ gitdir = toRawFilePath $ absPathFrom top $-					drop (length gitdirprefix) c+				{ gitdir = absPathFrom +					(toRawFilePath top)+					(toRawFilePath +						(drop (length gitdirprefix) c)) 				} 		else return Nothing  where
Git/CurrentRepo.hs view
@@ -1,10 +1,12 @@ {- The current git repository.  -- - Copyright 2012 Joey Hess <id@joeyh.name>+ - Copyright 2012-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.CurrentRepo where  import Common@@ -13,7 +15,11 @@ import qualified Git.Config import Utility.Env import Utility.Env.Set+import qualified Utility.RawFilePath as R +import qualified Data.ByteString as B+import qualified System.FilePath.ByteString as P+ {- Gets the current git repository.  -  - Honors GIT_DIR and GIT_WORK_TREE.@@ -37,14 +43,14 @@ 	gd <- getpathenv "GIT_DIR" 	r <- configure gd =<< fromCwd 	prefix <- getpathenv "GIT_PREFIX"-	wt <- maybe (fromRawFilePath <$> worktree (location r)) Just+	wt <- maybe (worktree (location r)) Just 		<$> getpathenvprefix "GIT_WORK_TREE" prefix 	case wt of 		Nothing -> return r 		Just d -> do-			curr <- getCurrentDirectory+			curr <- R.getCurrentDirectory 			unless (d `dirContains` curr) $-				setCurrentDirectory d+				setCurrentDirectory (fromRawFilePath d) 			return $ addworktree wt r   where 	getpathenv s = do@@ -52,24 +58,25 @@ 		case v of 			Just d -> do 				unsetEnv s-				return (Just d)+				return (Just (toRawFilePath d)) 			Nothing -> return Nothing 	-	getpathenvprefix s (Just prefix) | not (null prefix) =+	getpathenvprefix s (Just prefix) | not (B.null prefix) = 		getpathenv s >>= \case 			Nothing -> return Nothing 			Just d 				| d == "." -> return (Just d)-				| otherwise -> Just <$> absPath (prefix </> d)+				| otherwise -> Just +					<$> absPath (prefix P.</> d) 	getpathenvprefix s _ = getpathenv s  	configure Nothing (Just r) = Git.Config.read r 	configure (Just d) _ = do 		absd <- absPath d-		curr <- getCurrentDirectory+		curr <- R.getCurrentDirectory 		loc <- adjustGitDirFile $ Local-			{ gitdir = toRawFilePath absd-			, worktree = Just (toRawFilePath curr)+			{ gitdir = absd+			, worktree = Just curr 			} 		r <- Git.Config.read $ newFrom loc 		return $ if Git.Config.isBare r@@ -79,6 +86,7 @@  	addworktree w r = changelocation r $ Local 		{ gitdir = gitdir (location r)-		, worktree = fmap toRawFilePath w+		, worktree = w 		}+	 	changelocation r l = r { location = l }
Git/DiffTree.hs view
@@ -17,6 +17,7 @@ 	commitDiff, ) where +import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L import qualified Data.Attoparsec.ByteString.Lazy as A import qualified Data.Attoparsec.ByteString.Char8 as A8@@ -34,9 +35,11 @@ {- Checks if the DiffTreeItem modifies a file with a given name  - or under a directory by that name. -} isDiffOf :: DiffTreeItem -> TopFilePath -> Bool-isDiffOf diff f = case fromRawFilePath (getTopFilePath f) of-	"" -> True -- top of repo contains all-	d -> d `dirContains` fromRawFilePath (getTopFilePath (file diff))+isDiffOf diff f = +	let f' = getTopFilePath f+	in if B.null f'+		then True -- top of repo contains all+		else f' `dirContains` getTopFilePath (file diff)  {- Diffs two tree Refs. -} diffTree :: Ref -> Ref -> Repo -> IO ([DiffTreeItem], IO Bool)
Git/FilePath.hs view
@@ -58,8 +58,7 @@  {- The input FilePath can be absolute, or relative to the CWD. -} toTopFilePath :: RawFilePath -> Git.Repo -> IO TopFilePath-toTopFilePath file repo = TopFilePath . toRawFilePath-	<$> relPathDirToFile (fromRawFilePath (repoPath repo)) (fromRawFilePath file)+toTopFilePath file repo = TopFilePath <$> relPathDirToFile (repoPath repo) file  {- The input RawFilePath must already be relative to the top of the git  - repository -}
Git/Filename.hs view
@@ -10,6 +10,7 @@  import Common import Utility.Format (decode_c, encode_c)+import Utility.QuickCheck  import Data.Char import Data.Word@@ -35,21 +36,14 @@ encode :: RawFilePath -> S.ByteString encode s = encodeBS $ "\"" ++ encode_c (decodeBS s) ++ "\"" -prop_encode_decode_roundtrip :: FilePath -> Bool-prop_encode_decode_roundtrip s = s' ==-	fromRawFilePath (decode (encode (toRawFilePath s')))+-- Encoding and then decoding roundtrips only when the string does not+-- contain high unicode, because eg,  both "\12345" and "\227\128\185"+-- are encoded to "\343\200\271".+--+-- That is not a real-world problem, and using TestableFilePath+-- limits what's tested to ascii, so avoids running into it.+prop_encode_decode_roundtrip :: TestableFilePath -> Bool+prop_encode_decode_roundtrip ts = +	s == fromRawFilePath (decode (encode (toRawFilePath s)))   where-	s' = nonul (nohigh s)-	-- Encoding and then decoding roundtrips only when-	-- the string does not contain high unicode, because eg, -	-- both "\12345" and "\227\128\185" are encoded to-	-- "\343\200\271".-	---	-- This property papers over the problem, by only-	-- testing ascii-	nohigh = filter isAscii-	-- A String can contain a NUL, but toRawFilePath-	-- truncates on the NUL, which is generally fine-	-- because unix filenames cannot contain NUL.-	-- So the encoding only roundtrips when there is no nul.-	nonul = filter (/= '\NUL')+	s = fromTestableFilePath ts
Git/HashObject.hs view
@@ -36,10 +36,10 @@ hashObjectStop = CoProcess.stop  {- Injects a file into git, returning the Sha of the object. -}-hashFile :: HashObjectHandle -> FilePath -> IO Sha+hashFile :: HashObjectHandle -> RawFilePath -> IO Sha hashFile h file = CoProcess.query h send receive   where-	send to = hPutStrLn to =<< absPath file+	send to = S8.hPutStrLn to =<< absPath file 	receive from = getSha "hash-object" $ S8.hGetLine from  class HashableBlob t where@@ -60,7 +60,7 @@ hashBlob h b = withTmpFile "hash" $ \tmp tmph -> do 	hashableBlobToHandle tmph b 	hClose tmph-	hashFile h tmp+	hashFile h (toRawFilePath tmp)  {- Injects some content into git, returning its Sha.  - 
Git/Index.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.Index where  import Common@@ -12,6 +14,8 @@ import Utility.Env import Utility.Env.Set +import qualified System.FilePath.ByteString as P+ indexEnv :: String indexEnv = "GIT_INDEX_FILE" @@ -26,8 +30,8 @@  -  - So, an absolute path is the only safe option for this to return.  -}-indexEnvVal :: FilePath -> IO String-indexEnvVal = absPath+indexEnvVal :: RawFilePath -> IO String+indexEnvVal p = fromRawFilePath <$> absPath p  {- Forces git to use the specified index file.  -@@ -36,7 +40,7 @@  -  - Warning: Not thread safe.  -}-override :: FilePath -> Repo -> IO (IO ())+override :: RawFilePath -> Repo -> IO (IO ()) override index _r = do 	res <- getEnv var 	val <- indexEnvVal index@@ -48,13 +52,13 @@ 	reset _ = unsetEnv var  {- The normal index file. Does not check GIT_INDEX_FILE. -}-indexFile :: Repo -> FilePath-indexFile r = fromRawFilePath (localGitDir r) </> "index"+indexFile :: Repo -> RawFilePath+indexFile r = localGitDir r P.</> "index"  {- The index file git will currently use, checking GIT_INDEX_FILE. -}-currentIndexFile :: Repo -> IO FilePath-currentIndexFile r = fromMaybe (indexFile r) <$> getEnv indexEnv	+currentIndexFile :: Repo -> IO RawFilePath+currentIndexFile r = maybe (indexFile r) toRawFilePath <$> getEnv indexEnv  {- Git locks the index by creating this file. -}-indexFileLock :: FilePath -> FilePath-indexFileLock f = f ++ ".lock"+indexFileLock :: RawFilePath -> RawFilePath+indexFileLock f = f <> ".lock"
Git/LsFiles.hs view
@@ -37,12 +37,14 @@ import Utility.InodeCache import Utility.TimeStamp import Utility.Attoparsec+import qualified Utility.RawFilePath as R  import System.Posix.Types import qualified Data.Map as M import qualified Data.ByteString as S import qualified Data.Attoparsec.ByteString as A import qualified Data.Attoparsec.ByteString.Char8 as A8+import qualified System.FilePath.ByteString as P  {- It's only safe to use git ls-files on the current repo, not on a remote.  -@@ -208,12 +210,12 @@  typeChanged' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) typeChanged' ps l repo = guardSafeForLsFiles repo $ do-	(fs, cleanup) <- pipeNullSplit (prefix ++ ps ++ suffix) repo+	(fs, cleanup) <- pipeNullSplit' (prefix ++ ps ++ suffix) repo 	-- git diff returns filenames relative to the top of the git repo; 	-- convert to filenames relative to the cwd, like git ls-files.-	top <- absPath (fromRawFilePath (repoPath repo))-	currdir <- getCurrentDirectory-	return (map (\f -> toRawFilePath (relPathDirToFileAbs currdir $ top </> decodeBL' f)) fs, cleanup)+	top <- absPath (repoPath repo)+	currdir <- R.getCurrentDirectory+	return (map (\f -> relPathDirToFileAbs currdir $ top P.</> f) fs, cleanup)   where 	prefix =  		[ Param "diff"
Git/Objects.hs view
@@ -5,39 +5,45 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.Objects where  import Common import Git import Git.Sha -objectsDir :: Repo -> FilePath-objectsDir r = fromRawFilePath (localGitDir r) </> "objects"+import qualified Data.ByteString as B+import qualified System.FilePath.ByteString as P -packDir :: Repo -> FilePath-packDir r = objectsDir r </> "pack"+objectsDir :: Repo -> RawFilePath+objectsDir r = localGitDir r P.</> "objects" -packIdxFile :: FilePath -> FilePath-packIdxFile = flip replaceExtension "idx"+packDir :: Repo -> RawFilePath+packDir r = objectsDir r P.</> "pack" +packIdxFile :: RawFilePath -> RawFilePath+packIdxFile = flip P.replaceExtension "idx"+ listPackFiles :: Repo -> IO [FilePath] listPackFiles r = filter (".pack" `isSuffixOf`) -	<$> catchDefaultIO [] (dirContents $ packDir r)+	<$> catchDefaultIO [] (dirContents $ fromRawFilePath $ packDir r)  listLooseObjectShas :: Repo -> IO [Sha] listLooseObjectShas r = catchDefaultIO [] $ 	mapMaybe (extractSha . encodeBS . concat . reverse . take 2 . reverse . splitDirectories)-		<$> dirContentsRecursiveSkipping (== "pack") True (objectsDir r)+		<$> dirContentsRecursiveSkipping (== "pack") True (fromRawFilePath (objectsDir r)) -looseObjectFile :: Repo -> Sha -> FilePath-looseObjectFile r sha = objectsDir r </> prefix </> rest+looseObjectFile :: Repo -> Sha -> RawFilePath+looseObjectFile r sha = objectsDir r P.</> prefix P.</> rest   where-	(prefix, rest) = splitAt 2 (fromRef sha)+	(prefix, rest) = B.splitAt 2 (fromRef' sha)  listAlternates :: Repo -> IO [FilePath]-listAlternates r = catchDefaultIO [] (lines <$> readFile alternatesfile)+listAlternates r = catchDefaultIO [] $+	lines <$> readFile (fromRawFilePath alternatesfile)   where-	alternatesfile = objectsDir r </> "info" </> "alternates"+	alternatesfile = objectsDir r P.</> "info" P.</> "alternates"  {- A repository recently cloned with --shared will have one or more  - alternates listed, and contain no loose objects or packs. -}
Git/Queue.hs view
@@ -45,11 +45,11 @@ 	 - to as the queue grows. -} 	| InternalAction 		{ getRunner :: InternalActionRunner m-		, getInternalFiles :: [(FilePath, IO Bool)]+		, getInternalFiles :: [(RawFilePath, IO Bool)] 		}  {- The String must be unique for each internal action. -}-data InternalActionRunner m = InternalActionRunner String (Repo -> [(FilePath, IO Bool)] -> m ())+data InternalActionRunner m = InternalActionRunner String (Repo -> [(RawFilePath, IO Bool)] -> m ())  instance Eq (InternalActionRunner m) where 	InternalActionRunner s1 _ == InternalActionRunner s2 _ = s1 == s2@@ -108,7 +108,7 @@ 	different _ = True  {- Adds an internal action to the queue. -}-addInternalAction :: MonadIO m => InternalActionRunner m -> [(FilePath, IO Bool)] -> Queue m -> Repo -> m (Queue m)+addInternalAction :: MonadIO m => InternalActionRunner m -> [(RawFilePath, IO Bool)] -> Queue m -> Repo -> m (Queue m) addInternalAction runner files q repo = 	updateQueue action different (length files) q repo   where
Git/Repair.hs view
@@ -35,12 +35,15 @@ import qualified Git.RefLog as RefLog import qualified Git.UpdateIndex as UpdateIndex import qualified Git.Branch as Branch+import Utility.Directory.Create import Utility.Tmp.Dir import Utility.Rsync import Utility.FileMode+import qualified Utility.RawFilePath as R  import qualified Data.Set as S import qualified Data.ByteString.Lazy as L+import qualified System.FilePath.ByteString as P  {- Given a set of bad objects found by git fsck, which may not  - be complete, finds and removes all corrupt objects. -}@@ -50,9 +53,9 @@ 	mapM_ removeLoose (S.toList $ knownMissing fsckresults) 	mapM_ removeBad =<< listLooseObjectShas r   where-	removeLoose s = nukeFile (looseObjectFile r s)+	removeLoose s = removeWhenExistsWith R.removeLink (looseObjectFile r s) 	removeBad s = do-		void $ tryIO $ allowRead $  looseObjectFile r s+		void $ tryIO $ allowRead $ looseObjectFile r s 		whenM (isMissing s r) $ 			removeLoose s @@ -76,10 +79,11 @@ 		putStrLn "Unpacking all pack files." 		forM_ packs $ \packfile -> do 			moveFile packfile (tmpdir </> takeFileName packfile)-			nukeFile $ packIdxFile packfile+			removeWhenExistsWith R.removeLink+				(packIdxFile (toRawFilePath packfile)) 		forM_ packs $ \packfile -> do 			let tmp = tmpdir </> takeFileName packfile-			allowRead tmp+			allowRead (toRawFilePath tmp) 			-- May fail, if pack file is corrupt. 			void $ tryIO $ 				pipeWrite [Param "unpack-objects", Param "-r"] r $ \h ->@@ -99,7 +103,7 @@ 	| otherwise = withTmpDir "tmprepo" $ \tmpdir -> do 		unlessM (boolSystem "git" [Param "init", File tmpdir]) $ 			error $ "failed to create temp repository in " ++ tmpdir-		tmpr <- Config.read =<< Construct.fromAbsPath tmpdir+		tmpr <- Config.read =<< Construct.fromAbsPath (toRawFilePath tmpdir) 		rs <- Construct.fromRemotes r 		stillmissing <- pullremotes tmpr rs fetchrefstags missing 		if S.null (knownMissing stillmissing)@@ -160,8 +164,8 @@ copyObjects :: Repo -> Repo -> IO Bool copyObjects srcr destr = rsync 	[ Param "-qr"-	, File $ addTrailingPathSeparator $ objectsDir srcr-	, File $ addTrailingPathSeparator $ objectsDir destr+	, File $ addTrailingPathSeparator $ fromRawFilePath $ objectsDir srcr+	, File $ addTrailingPathSeparator $ fromRawFilePath $ objectsDir destr 	]  {- To deal with missing objects that cannot be recovered, resets any@@ -243,14 +247,15 @@ 		rs <- mapMaybe parsePacked . lines 			<$> catchDefaultIO "" (safeReadFile f) 		forM_ rs makeref-		nukeFile f+		removeWhenExistsWith removeLink f   where 	makeref (sha, ref) = do-		let gitd = fromRawFilePath (localGitDir r)-		let dest = gitd </> fromRef ref+		let gitd = localGitDir r+		let dest = gitd P.</> fromRef' ref+		let dest' = fromRawFilePath dest 		createDirectoryUnder gitd (parentDir dest)-		unlessM (doesFileExist dest) $-			writeFile dest (fromRef sha)+		unlessM (doesFileExist dest') $+			writeFile dest' (fromRef sha)  packedRefsFile :: Repo -> FilePath packedRefsFile r = fromRawFilePath (localGitDir r) </> "packed-refs"@@ -265,7 +270,7 @@ {- git-branch -d cannot be used to remove a branch that is directly  - pointing to a corrupt commit. -} nukeBranchRef :: Branch -> Repo -> IO ()-nukeBranchRef b r = nukeFile $ fromRawFilePath (localGitDir r) </> fromRef b+nukeBranchRef b r = removeWhenExistsWith R.removeLink $ localGitDir r P.</> fromRef' b  {- Finds the most recent commit to a branch that does not need any  - of the missing objects. If the input branch is good as-is, returns it.@@ -391,7 +396,7 @@ 	| otherwise = do 		(bad, good, cleanup) <- partitionIndex r 		unless (null bad) $ do-			nukeFile (indexFile r)+			removeWhenExistsWith R.removeLink (indexFile r) 			UpdateIndex.streamUpdateIndex r 				=<< (catMaybes <$> mapM reinject good) 		void cleanup@@ -439,12 +444,11 @@ preRepair :: Repo -> IO () preRepair g = do 	unlessM (validhead <$> catchDefaultIO "" (safeReadFile headfile)) $ do-		nukeFile headfile+		removeWhenExistsWith removeLink headfile 		writeFile headfile "ref: refs/heads/master" 	explodePackedRefsFile g-	unless (repoIsLocalBare g) $ do-		let f = indexFile g-		void $ tryIO $ allowWrite f+	unless (repoIsLocalBare g) $+		void $ tryIO $ allowWrite $ indexFile g   where 	headfile = fromRawFilePath (localGitDir g) </> "HEAD" 	validhead s = "ref: refs/" `isPrefixOf` s@@ -568,7 +572,7 @@ 			else successfulfinish modifiedbranches  	corruptedindex = do-		nukeFile (indexFile g)+		removeWhenExistsWith R.removeLink (indexFile g) 		-- The corrupted index can prevent fsck from finding other 		-- problems, so re-run repair. 		fsckresult' <- findBroken False g@@ -614,5 +618,5 @@  safeReadFile :: FilePath -> IO String safeReadFile f = do-	allowRead f+	allowRead (toRawFilePath f) 	readFileStrict f
Git/Types.hs view
@@ -5,7 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} -{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, FlexibleInstances #-}  module Git.Types where @@ -79,9 +79,15 @@ instance Show ConfigKey where 	show = fromConfigKey -fromConfigValue :: ConfigValue -> String-fromConfigValue (ConfigValue s) = decodeBS' s-fromConfigValue NoConfigValue = mempty+class FromConfigValue a where+	fromConfigValue :: ConfigValue -> a++instance FromConfigValue S.ByteString where+	fromConfigValue (ConfigValue s) = s+	fromConfigValue NoConfigValue = mempty++instance FromConfigValue String where+	fromConfigValue = decodeBS' . fromConfigValue  instance Show ConfigValue where 	show = fromConfigValue
Git/UpdateIndex.hs view
@@ -31,6 +31,7 @@ import Git.Sha import qualified Git.DiffTreeItem as Diff +import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import Control.Monad.IO.Class @@ -117,12 +118,12 @@ 	<> indexPath p  {- A streamer that adds a symlink to the index. -}-stageSymlink :: FilePath -> Sha -> Repo -> IO Streamer+stageSymlink :: RawFilePath -> Sha -> Repo -> IO Streamer stageSymlink file sha repo = do 	!line <- updateIndexLine 		<$> pure sha 		<*> pure TreeSymlink-		<*> toTopFilePath (toRawFilePath file) repo+		<*> toTopFilePath file repo 	return $ pureStreamer line  {- A streamer that applies a DiffTreeItem to the index. -}@@ -135,7 +136,7 @@ indexPath = toInternalGitPath . getTopFilePath  {- Refreshes the index, by checking file stat information.  -}-refreshIndex :: Repo -> ((FilePath -> IO ()) -> IO ()) -> IO Bool+refreshIndex :: Repo -> ((RawFilePath -> IO ()) -> IO ()) -> IO Bool refreshIndex repo feeder = withCreateProcess p go   where 	params = @@ -150,9 +151,8 @@ 		{ std_in = CreatePipe }  	go (Just h) _ _ pid = do-		feeder $ \f -> do-			hPutStr h f-			hPutStr h "\0"+		feeder $ \f ->+			S.hPut h (S.snoc f 0) 		hFlush h 		hClose h 		checkSuccessProcess pid
Git/Version.hs view
@@ -14,7 +14,7 @@ 	GitVersion, ) where -import Common+import Utility.Process import Utility.DottedVersion  type GitVersion = DottedVersion
Key.hs view
@@ -31,7 +31,6 @@ 	prop_isomorphic_key_encode ) where -import Data.Char import qualified Data.Text as T import qualified Data.ByteString as S import qualified Data.Attoparsec.ByteString as A@@ -100,16 +99,10 @@ 		<*> ((abs <$>) <$> arbitrary) -- chunksize cannot be negative 		<*> ((succ . abs <$>) <$> arbitrary) -- chunknum cannot be 0 or negative --- AssociatedFile cannot be empty, and cannot contain a NUL--- (but can be Nothing).  instance Arbitrary AssociatedFile where-  	arbitrary = (AssociatedFile . fmap conv <$> arbitrary)-		`suchThat` (/= AssociatedFile (Just S.empty))-		`suchThat` (\(AssociatedFile f) -> maybe True (S.notElem 0) f)-	  where-		-- Generating arbitrary unicode leads to encoding errors-		-- when LANG=C, so limit to ascii.-		conv = toRawFilePath . filter isAscii+  	arbitrary = AssociatedFile+		. fmap (toRawFilePath . fromTestableFilePath)+		<$> arbitrary  instance Arbitrary Key where 	arbitrary = mkKey . const <$> arbitrary
Limit.hs view
@@ -333,7 +333,7 @@ 			then approxNumCopies 			else case mi of 				MatchingFile fi -> getGlobalFileNumCopies $-					fromRawFilePath $ matchFile fi+					matchFile fi 				MatchingKey _ _ -> approxNumCopies 				MatchingInfo {} -> approxNumCopies 				MatchingUserInfo {} -> approxNumCopies@@ -464,8 +464,7 @@ 		LimitAnnexFiles -> goannexed sz fi 		LimitDiskFiles -> case contentFile fi of 			Just f -> do-				filesize <- liftIO $ catchMaybeIO $-					getFileSize (fromRawFilePath f)+				filesize <- liftIO $ catchMaybeIO $ getFileSize f 				return $ filesize `vs` Just sz 			Nothing -> goannexed sz fi 	go sz _ (MatchingKey key _) = checkkey sz key
Logs/Export.hs view
@@ -180,7 +180,8 @@ getExportExcluded :: UUID -> Annex [Git.Tree.TreeItem] getExportExcluded u = do 	logf <- fromRepo $ gitAnnexExportExcludeLog u-	liftIO $ catchDefaultIO [] $ parser <$> L.readFile logf+	liftIO $ catchDefaultIO [] $ parser+		<$> L.readFile (fromRawFilePath logf)   where 	parser = map Git.Tree.lsTreeItemToTreeItem 		. rights
Logs/File.hs view
@@ -29,32 +29,37 @@ -- | Writes content to a file, replacing the file atomically, and -- making the new file have whatever permissions the git repository is -- configured to use. Creates the parent directory when necessary.-writeLogFile :: FilePath -> String -> Annex ()-writeLogFile f c = createDirWhenNeeded f $ viaTmp writelog f c+writeLogFile :: RawFilePath -> String -> Annex ()+writeLogFile f c = createDirWhenNeeded f $ viaTmp writelog (fromRawFilePath f) c   where-	writelog f' c' = do-		liftIO $ writeFile f' c'-		setAnnexFilePerm f'+	writelog tmp c' = do+		liftIO $ writeFile tmp c'+		setAnnexFilePerm (toRawFilePath tmp)  -- | Runs the action with a handle connected to a temp file. -- The temp file replaces the log file once the action succeeds.-withLogHandle :: FilePath -> (Handle -> Annex a) -> Annex a+withLogHandle :: RawFilePath -> (Handle -> Annex a) -> Annex a withLogHandle f a = do 	createAnnexDirectory (parentDir f)-	replaceGitAnnexDirFile f $ \tmp ->+	replaceGitAnnexDirFile (fromRawFilePath f) $ \tmp -> 		bracket (setup tmp) cleanup a   where 	setup tmp = do-		setAnnexFilePerm tmp+		setAnnexFilePerm (toRawFilePath tmp) 		liftIO $ openFile tmp WriteMode 	cleanup h = liftIO $ hClose h  -- | Appends a line to a log file, first locking it to prevent -- concurrent writers.-appendLogFile :: FilePath -> (Git.Repo -> FilePath) -> L.ByteString -> Annex ()-appendLogFile f lck c = createDirWhenNeeded f $ withExclusiveLock lck $ do-	liftIO $ withFile f AppendMode $ \h -> L8.hPutStrLn h c-	setAnnexFilePerm f+appendLogFile :: RawFilePath -> (Git.Repo -> RawFilePath) -> L.ByteString -> Annex ()+appendLogFile f lck c = +	createDirWhenNeeded f $+		withExclusiveLock lck $ do+			liftIO $ withFile f' AppendMode $+				\h -> L8.hPutStrLn h c+			setAnnexFilePerm (toRawFilePath f')+  where+	f' = fromRawFilePath f  -- | Modifies a log file. --@@ -64,18 +69,19 @@ -- -- The file is locked to prevent concurrent writers, and it is written -- atomically.-modifyLogFile :: FilePath -> (Git.Repo -> FilePath) -> ([L.ByteString] -> [L.ByteString]) -> Annex ()+modifyLogFile :: RawFilePath -> (Git.Repo -> RawFilePath) -> ([L.ByteString] -> [L.ByteString]) -> Annex () modifyLogFile f lck modf = withExclusiveLock lck $ do 	ls <- liftIO $ fromMaybe []-		<$> tryWhenExists (L8.lines <$> L.readFile f)+		<$> tryWhenExists (L8.lines <$> L.readFile f') 	let ls' = modf ls 	when (ls' /= ls) $ 		createDirWhenNeeded f $-			viaTmp writelog f (L8.unlines ls')+			viaTmp writelog f' (L8.unlines ls')   where-	writelog f' b = do-		liftIO $ L.writeFile f' b-		setAnnexFilePerm f'+	f' = fromRawFilePath f+	writelog lf b = do+		liftIO $ L.writeFile lf b+		setAnnexFilePerm (toRawFilePath lf)  -- | Checks the content of a log file to see if any line matches. --@@ -83,7 +89,7 @@ -- action is concurrently modifying the file. It does not lock the file, -- for speed, but instead relies on the fact that a log file usually -- ends in a newline.-checkLogFile :: FilePath -> (Git.Repo -> FilePath) -> (L.ByteString -> Bool) -> Annex Bool+checkLogFile :: FilePath -> (Git.Repo -> RawFilePath) -> (L.ByteString -> Bool) -> Annex Bool checkLogFile f lck matchf = withExclusiveLock lck $ bracket setup cleanup go   where 	setup = liftIO $ tryWhenExists $ openFile f ReadMode@@ -117,7 +123,7 @@ --  -- Locking is used to prevent writes to to the log file while this -- is running.-streamLogFile :: FilePath -> (Git.Repo -> FilePath) -> (String -> Annex ()) -> Annex ()+streamLogFile :: FilePath -> (Git.Repo -> RawFilePath) -> (String -> Annex ()) -> Annex () streamLogFile f lck a = withExclusiveLock lck $ bracketOnError setup cleanup go   where 	setup = liftIO $ tryWhenExists $ openFile f ReadMode @@ -128,9 +134,9 @@ 		mapM_ a =<< liftIO (lines <$> hGetContents h) 		liftIO $ hClose h 		liftIO $ writeFile f ""-		setAnnexFilePerm f+		setAnnexFilePerm (toRawFilePath f) -createDirWhenNeeded :: FilePath -> Annex () -> Annex ()+createDirWhenNeeded :: RawFilePath -> Annex () -> Annex () createDirWhenNeeded f a = a `catchNonAsync` \_e -> do 	-- Most of the time, the directory will exist, so this is only 	-- done if writing the file fails.
Logs/FsckResults.hs view
@@ -15,6 +15,7 @@ import Git.Fsck import Git.Types import Logs.File+import qualified Utility.RawFilePath as R  import qualified Data.Set as S @@ -24,7 +25,8 @@ 	case fsckresults of 		FsckFailed -> store S.empty False logfile 		FsckFoundMissing s t-			| S.null s -> liftIO $ nukeFile logfile+			| S.null s -> liftIO $+				removeWhenExistsWith R.removeLink logfile 			| otherwise -> store s t logfile   where 	store s t logfile = writeLogFile logfile $ serialize s t@@ -38,7 +40,7 @@ readFsckResults u = do 	logfile <- fromRepo $ gitAnnexFsckResultsLog u 	liftIO $ catchDefaultIO (FsckFoundMissing S.empty False) $-		deserialize . lines <$> readFile logfile+		deserialize . lines <$> readFile (fromRawFilePath logfile)   where 	deserialize ("truncated":ls) = deserialize' ls True 	deserialize ls = deserialize' ls False@@ -47,5 +49,6 @@ 		in if S.null s then FsckFailed else FsckFoundMissing s t  clearFsckResults :: UUID -> Annex ()-clearFsckResults = liftIO . nukeFile <=< fromRepo . gitAnnexFsckResultsLog+clearFsckResults = liftIO . removeWhenExistsWith R.removeLink+	<=< fromRepo . gitAnnexFsckResultsLog 	
Logs/Remote/Pure.hs view
@@ -22,6 +22,7 @@ import Types.ProposedAccepted import Logs.UUIDBased import Annex.SpecialRemote.Config+import Utility.QuickCheck  import qualified Data.ByteString.Lazy as L import qualified Data.Map as M@@ -85,8 +86,10 @@ 		rest = drop 1 r  {- for quickcheck -}-prop_isomorphic_configEscape :: String -> Bool-prop_isomorphic_configEscape s = s == (configUnEscape . configEscape) s+prop_isomorphic_configEscape :: TestableString -> Bool+prop_isomorphic_configEscape ts = s == (configUnEscape . configEscape) s+  where+	s = fromTestableString ts  prop_parse_show_Config :: RemoteConfig -> Bool prop_parse_show_Config c
Logs/Schedule.hs view
@@ -63,7 +63,7 @@  getLastRunTimes :: Annex (M.Map ScheduledActivity LocalTime) getLastRunTimes = do-	f <- fromRepo gitAnnexScheduleState+	f <- fromRawFilePath <$> fromRepo gitAnnexScheduleState 	liftIO $ fromMaybe M.empty 		<$> catchDefaultIO Nothing (readish <$> readFile f) 
Logs/Smudge.hs view
@@ -32,7 +32,7 @@ streamSmudged :: (Key -> TopFilePath -> Annex ()) -> Annex () streamSmudged a = do 	logf <- fromRepo gitAnnexSmudgeLog-	streamLogFile logf gitAnnexSmudgeLock $ \l -> +	streamLogFile (fromRawFilePath logf) gitAnnexSmudgeLock $ \l ->  		case parse l of 			Nothing -> noop 			Just (k, f) -> a k f
Logs/Transfer.hs view
@@ -5,6 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}  module Logs.Transfer where@@ -19,6 +20,7 @@ import Annex.LockPool import Utility.TimeStamp import Logs.File+import qualified Utility.RawFilePath as R #ifndef mingw32_HOST_OS import Annex.Perms #endif@@ -26,6 +28,8 @@ import Data.Time.Clock import Data.Time.Clock.POSIX import Control.Concurrent+import qualified Data.ByteString.Char8 as B8+import qualified System.FilePath.ByteString as P  describeTransfer :: Transfer -> TransferInfo -> String describeTransfer t info = unwords@@ -56,12 +60,12 @@  - which should be run after locking the transfer lock file, but  - before using the callback, and a MVar that can be used to read  - the number of bytesComplete. -}-mkProgressUpdater :: Transfer -> TransferInfo -> Annex (MeterUpdate, FilePath, Annex (), MVar Integer)+mkProgressUpdater :: Transfer -> TransferInfo -> Annex (MeterUpdate, RawFilePath, Annex (), MVar Integer) mkProgressUpdater t info = do 	tfile <- fromRepo $ transferFile t 	let createtfile = void $ tryNonAsync $ writeTransferInfoFile info tfile 	mvar <- liftIO $ newMVar 0-	return (liftIO . updater tfile mvar, tfile, createtfile, mvar)+	return (liftIO . updater (fromRawFilePath tfile) mvar, tfile, createtfile, mvar)   where 	updater tfile mvar b = modifyMVar_ mvar $ \oldbytes -> do 		let newbytes = fromBytesProcessed b@@ -103,13 +107,13 @@ 	tfile <- fromRepo $ transferFile t 	let lck = transferLockFile tfile 	let cleanstale = do-		void $ tryIO $ removeFile tfile-		void $ tryIO $ removeFile lck+		void $ tryIO $ R.removeLink tfile+		void $ tryIO $ R.removeLink lck #ifndef mingw32_HOST_OS 	v <- getLockStatus lck 	case v of 		StatusLockedBy pid -> liftIO $ catchDefaultIO Nothing $-			readTransferInfoFile (Just pid) tfile+			readTransferInfoFile (Just pid) (fromRawFilePath tfile) 		_ -> do 			-- Take a non-blocking lock while deleting 			-- the stale lock file. Ignore failure@@ -145,7 +149,7 @@ 	infos <- mapM checkTransfer transfers 	return $ mapMaybe running $ zip transfers infos   where-	findfiles = liftIO . mapM dirContentsRecursive+	findfiles = liftIO . mapM (dirContentsRecursive . fromRawFilePath) 		=<< mapM (fromRepo . transferDir) dirs 	running (t, Just i) = Just (t, i) 	running (_, Nothing) = Nothing@@ -172,7 +176,7 @@ 		return $ case (mt, mi) of 			(Just t, Just i) -> Just (t, i) 			_ -> Nothing-	findfiles = liftIO . mapM dirContentsRecursive+	findfiles = liftIO . mapM (dirContentsRecursive . fromRawFilePath) 		=<< mapM (fromRepo . failedTransferDir u) [Download, Upload]  clearFailedTransfers :: UUID -> Annex [(Transfer, TransferInfo)]@@ -184,7 +188,7 @@ removeFailedTransfer :: Transfer -> Annex () removeFailedTransfer t = do 	f <- fromRepo $ failedTransferFile t-	liftIO $ void $ tryIO $ removeFile f+	liftIO $ void $ tryIO $ R.removeLink f  recordFailedTransfer :: Transfer -> TransferInfo -> Annex () recordFailedTransfer t info = do@@ -192,20 +196,23 @@ 	writeTransferInfoFile info failedtfile  {- The transfer information file to use for a given Transfer. -}-transferFile :: Transfer -> Git.Repo -> FilePath-transferFile (Transfer direction u kd) r = transferDir direction r-	</> filter (/= '/') (fromUUID u)-	</> fromRawFilePath (keyFile (mkKey (const kd)))+transferFile :: Transfer -> Git.Repo -> RawFilePath+transferFile (Transfer direction u kd) r =+	transferDir direction r+		P.</> B8.filter (/= '/') (fromUUID u)+		P.</> keyFile (mkKey (const kd))  {- The transfer information file to use to record a failed Transfer -}-failedTransferFile :: Transfer -> Git.Repo -> FilePath-failedTransferFile (Transfer direction u kd) r = failedTransferDir u direction r-	</> fromRawFilePath (keyFile (mkKey (const kd)))+failedTransferFile :: Transfer -> Git.Repo -> RawFilePath+failedTransferFile (Transfer direction u kd) r = +	failedTransferDir u direction r+		P.</> keyFile (mkKey (const kd))  {- The transfer lock file corresponding to a given transfer info file. -}-transferLockFile :: FilePath -> FilePath-transferLockFile infofile = let (d,f) = splitFileName infofile in-	combine d ("lck." ++ f)+transferLockFile :: RawFilePath -> RawFilePath+transferLockFile infofile = +	let (d, f) = P.splitFileName infofile+	in P.combine d ("lck." <> f)  {- Parses a transfer information filename to a Transfer. -} parseTransferFile :: FilePath -> Maybe Transfer@@ -220,7 +227,7 @@   where 	bits = splitDirectories file -writeTransferInfoFile :: TransferInfo -> FilePath -> Annex ()+writeTransferInfoFile :: TransferInfo -> RawFilePath -> Annex () writeTransferInfoFile info tfile = writeLogFile tfile $ writeTransferInfo info  -- The file keeps whatever permissions it has, so should be used only@@ -286,16 +293,16 @@ 		else pure Nothing -- not failure  {- The directory holding transfer information files for a given Direction. -}-transferDir :: Direction -> Git.Repo -> FilePath-transferDir direction r = gitAnnexTransferDir r </> formatDirection direction+transferDir :: Direction -> Git.Repo -> RawFilePath+transferDir direction r = gitAnnexTransferDir r P.</> formatDirection direction  {- The directory holding failed transfer information files for a given  - Direction and UUID -}-failedTransferDir :: UUID -> Direction -> Git.Repo -> FilePath+failedTransferDir :: UUID -> Direction -> Git.Repo -> RawFilePath failedTransferDir u direction r = gitAnnexTransferDir r-	</> "failed"-	</> formatDirection direction-	</> filter (/= '/') (fromUUID u)+	P.</> "failed"+	P.</> formatDirection direction+	P.</> B8.filter (/= '/') (fromUUID u)  prop_read_write_transferinfo :: TransferInfo -> Bool prop_read_write_transferinfo info
Logs/Unused.hs view
@@ -15,6 +15,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Logs.Unused ( 	UnusedMap, 	updateUnusedLog,@@ -55,13 +57,13 @@   where 	oldts _old@(_, ts) _new@(int, _) = (int, ts) -updateUnusedLog :: FilePath -> UnusedMap -> Annex ()+updateUnusedLog :: RawFilePath -> UnusedMap -> Annex () updateUnusedLog prefix m = do 	oldl <- readUnusedLog prefix 	newl <- preserveTimestamps oldl . flip map2log m <$> liftIO getPOSIXTime 	writeUnusedLog prefix newl -writeUnusedLog :: FilePath -> UnusedLog -> Annex ()+writeUnusedLog :: RawFilePath -> UnusedLog -> Annex () writeUnusedLog prefix l = do 	logfile <- fromRepo $ gitAnnexUnusedLog prefix 	writeLogFile logfile $ unlines $ map format $ M.toList l@@ -69,9 +71,9 @@ 	format (k, (i, Just t)) = show i ++ " " ++ serializeKey k ++ " " ++ show t 	format (k, (i, Nothing)) = show i ++ " " ++ serializeKey k -readUnusedLog :: FilePath -> Annex UnusedLog+readUnusedLog :: RawFilePath -> Annex UnusedLog readUnusedLog prefix = do-	f <- fromRepo $ gitAnnexUnusedLog prefix+	f <- fromRawFilePath <$> fromRepo (gitAnnexUnusedLog prefix) 	ifM (liftIO $ doesFileExist f) 		( M.fromList . mapMaybe parse . lines 			<$> liftIO (readFileStrict f)@@ -87,13 +89,13 @@ 		skey = reverse rskey 		ts = reverse rts -readUnusedMap :: FilePath -> Annex UnusedMap+readUnusedMap :: RawFilePath -> Annex UnusedMap readUnusedMap = log2map <$$> readUnusedLog -dateUnusedLog :: FilePath -> Annex (Maybe UTCTime)+dateUnusedLog :: RawFilePath -> Annex (Maybe UTCTime) dateUnusedLog prefix = do 	f <- fromRepo $ gitAnnexUnusedLog prefix-	liftIO $ catchMaybeIO $ getModificationTime f+	liftIO $ catchMaybeIO $ getModificationTime $ fromRawFilePath f  {- Set of unused keys. This is cached for speed. -} unusedKeys :: Annex (S.Set Key)
Logs/View.hs view
@@ -50,7 +50,7 @@  recentViews :: Annex [View] recentViews = do-	f <- fromRepo gitAnnexViewLog+	f <- fromRawFilePath <$> fromRepo gitAnnexViewLog 	liftIO $ mapMaybe readish . lines <$> catchDefaultIO [] (readFile f)  {- Gets the currently checked out view, if there is one. -}
Messages/Progress.hs view
@@ -49,7 +49,7 @@  - This allows uploads of keys without size to still have progress  - displayed.  -}-data KeySizer = KeySizer Key (Annex (Maybe FilePath))+data KeySizer = KeySizer Key (Annex (Maybe RawFilePath))  instance MeterSize KeySizer where 	getMeterSize (KeySizer k getsrcfile) = case fromKey keySize k of
P2P/Annex.hs view
@@ -43,10 +43,10 @@ 		size <- liftIO $ catchDefaultIO 0 $ getFileSize tmp 		runner (next (Len size)) 	FileSize f next -> do-		size <- liftIO $ catchDefaultIO 0 $ getFileSize f+		size <- liftIO $ catchDefaultIO 0 $ getFileSize (toRawFilePath f) 		runner (next (Len size)) 	ContentSize k next -> do-		let getsize = liftIO . catchMaybeIO . getFileSize . fromRawFilePath+		let getsize = liftIO . catchMaybeIO . getFileSize 		size <- inAnnex' isJust Nothing getsize k 		runner (next (Len <$> size)) 	ReadContent k af o sender next -> do@@ -77,7 +77,7 @@ 			let runtransfer ti =  				Right <$> transfer download k af (\p -> 					getViaTmp rsp DefaultVerify k $ \tmp ->-						storefile tmp o l getb validitycheck p ti)+						storefile (fromRawFilePath tmp) o l getb validitycheck p ti) 			let fallback = return $ Left $ 				ProtoFailureMessage "transfer already in progress, or unable to take transfer lock" 			checktransfer runtransfer fallback@@ -166,7 +166,7 @@ 				indicatetransferred ti  				rightsize <- do-					sz <- liftIO $ getFileSize dest+					sz <- liftIO $ getFileSize (toRawFilePath dest) 					return (toInteger sz == l + o) 					 				runner validitycheck >>= \case
P2P/IO.hs view
@@ -124,7 +124,7 @@ -- the callback. serveUnixSocket :: FilePath -> (Handle -> IO ()) -> IO () serveUnixSocket unixsocket serveconn = do-	nukeFile unixsocket+	removeWhenExistsWith removeLink unixsocket 	soc <- S.socket S.AF_UNIX S.Stream S.defaultProtocol 	S.bind soc (S.SockAddrUnix unixsocket) 	-- Allow everyone to read and write to the socket,@@ -135,7 +135,7 @@         -- Connections have to authenticate to do anything,         -- so it's fine that other local users can connect to the         -- socket.-	modifyFileMode unixsocket $ addModes+	modifyFileMode (toRawFilePath unixsocket) $ addModes 		[groupReadMode, groupWriteMode, otherReadMode, otherWriteMode] 	S.listen soc 2 	forever $ do
Remote/BitTorrent.hs view
@@ -5,6 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}  module Remote.BitTorrent (remote) where@@ -29,8 +30,10 @@ import qualified Annex.Url as Url import Remote.Helper.ExportImport import Annex.SpecialRemote.Config+import qualified Utility.RawFilePath as R  import Network.URI+import qualified System.FilePath.ByteString as P  #ifdef WITH_TORRENTPARSER import Data.Torrent@@ -167,7 +170,7 @@ torrentUrlKey u = return $ fromUrl (fst $ torrentUrlNum u) Nothing  {- Temporary filename to use to store the torrent file. -}-tmpTorrentFile :: URLString -> Annex FilePath+tmpTorrentFile :: URLString -> Annex RawFilePath tmpTorrentFile u = fromRepo . gitAnnexTmpObjectLocation =<< torrentUrlKey u  {- A cleanup action is registered to delete the torrent file@@ -179,34 +182,37 @@  -} registerTorrentCleanup :: URLString -> Annex () registerTorrentCleanup u = Annex.addCleanup (TorrentCleanup u) $-	liftIO . nukeFile =<< tmpTorrentFile u+	liftIO . removeWhenExistsWith R.removeLink =<< tmpTorrentFile u  {- Downloads the torrent file. (Not its contents.) -} downloadTorrentFile :: URLString -> Annex Bool downloadTorrentFile u = do 	torrent <- tmpTorrentFile u-	ifM (liftIO $ doesFileExist torrent)+	ifM (liftIO $ doesFileExist (fromRawFilePath torrent)) 		( return True 		, do 			showAction "downloading torrent file" 			createAnnexDirectory (parentDir torrent) 			if isTorrentMagnetUrl u 				then withOtherTmp $ \othertmp -> do-					kf <- fromRawFilePath . keyFile <$> torrentUrlKey u-					let metadir = othertmp </> "torrentmeta" </> kf+					kf <- keyFile <$> torrentUrlKey u+					let metadir = othertmp P.</> "torrentmeta" P.</> kf 					createAnnexDirectory metadir 					showOutput-					ok <- downloadMagnetLink u metadir torrent-					liftIO $ removeDirectoryRecursive metadir+					ok <- downloadMagnetLink u+						(fromRawFilePath metadir)+						(fromRawFilePath torrent)+					liftIO $ removeDirectoryRecursive+						(fromRawFilePath metadir) 					return ok 				else withOtherTmp $ \othertmp -> do-					withTmpFileIn othertmp "torrent" $ \f h -> do+					withTmpFileIn (fromRawFilePath othertmp) "torrent" $ \f h -> do 						liftIO $ hClose h-						resetAnnexFilePerm f+						resetAnnexFilePerm (toRawFilePath f) 						ok <- Url.withUrlOptions $  							Url.download nullMeterUpdate u f 						when ok $-							liftIO $ renameFile f torrent+							liftIO $ renameFile f (fromRawFilePath torrent) 						return ok 		) @@ -237,14 +243,15 @@ downloadTorrentContent k u dest filenum p = do 	torrent <- tmpTorrentFile u 	withOtherTmp $ \othertmp -> do-		kf <- fromRawFilePath . keyFile <$> torrentUrlKey u-		let downloaddir = othertmp </> "torrent" </> kf+		kf <- keyFile <$> torrentUrlKey u+		let downloaddir = othertmp P.</> "torrent" P.</> kf 		createAnnexDirectory downloaddir 		f <- wantedfile torrent+		let dlf = fromRawFilePath downloaddir </> f 		showOutput-		ifM (download torrent downloaddir <&&> liftIO (doesFileExist (downloaddir </> f)))+		ifM (download torrent downloaddir <&&> liftIO (doesFileExist dlf)) 			( do-				liftIO $ renameFile (downloaddir </> f) dest+				liftIO $ renameFile dlf dest 				-- The downloaddir is not removed here, 				-- so if aria downloaded parts of other 				-- files, and this is called again, it will@@ -258,9 +265,9 @@   where 	download torrent tmpdir = ariaProgress (fromKey keySize k) p 		[ Param $ "--select-file=" ++ show filenum-		, File torrent+		, File (fromRawFilePath torrent) 		, Param "-d"-		, File tmpdir+		, File (fromRawFilePath tmpdir) 		, Param "--seed-time=0" 		, Param "--summary-interval=0" 		, Param "--file-allocation=none"@@ -347,11 +354,11 @@ {- Examines the torrent file and gets the list of files in it,  - and their sizes.  -}-torrentFileSizes :: FilePath -> IO [(FilePath, Integer)]+torrentFileSizes :: RawFilePath -> IO [(FilePath, Integer)] torrentFileSizes torrent = do #ifdef WITH_TORRENTPARSER 	let mkfile = joinPath . map (scrub . decodeBL)-	b <- B.readFile torrent+	b <- B.readFile (fromRawFilePath torrent) 	return $ case readTorrent b of 		Left e -> giveup $ "failed to parse torrent: " ++ e 		Right t -> case tInfo t of
Remote/Bup.hs view
@@ -285,11 +285,11 @@ bup2GitRemote "" = do 	-- bup -r "" operates on ~/.bup 	h <- myHomeDir-	Git.Construct.fromAbsPath $ h </> ".bup"+	Git.Construct.fromAbsPath $ toRawFilePath $ h </> ".bup" bup2GitRemote r 	| bupLocal r =  		if "/" `isPrefixOf` r-			then Git.Construct.fromAbsPath r+			then Git.Construct.fromAbsPath (toRawFilePath r) 			else giveup "please specify an absolute path" 	| otherwise = Git.Construct.fromUrl $ "ssh://" ++ host ++ slash dir   where
Remote/Directory.hs view
@@ -5,6 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}  module Remote.Directory (@@ -15,6 +16,7 @@  import qualified Data.ByteString.Lazy as L import qualified Data.Map as M+import qualified System.FilePath.ByteString as P import Data.Default  import Annex.Common@@ -25,7 +27,6 @@ import Config.Cost import Config import Annex.SpecialRemote.Config-import Utility.FileMode import Remote.Helper.Special import Remote.Helper.ExportImport import Types.Import@@ -35,10 +36,13 @@ import Annex.UUID import Backend import Types.KeySource+import Types.ProposedAccepted import Utility.Metered import Utility.Tmp import Utility.InodeCache-import Types.ProposedAccepted+import Utility.FileMode+import Utility.Directory.Create+import qualified Utility.RawFilePath as R  remote :: RemoteType remote = specialRemoteType $ RemoteType@@ -106,20 +110,21 @@ 			, config = c 			, getRepo = return r 			, gitconfig = gc-			, localpath = Just dir+			, localpath = Just dir' 			, readonly = False 			, appendonly = False 			, availability = LocallyAvailable 			, remotetype = remote 			, mkUnavailable = gen r u rc 				(gc { remoteAnnexDirectory = Just "/dev/null" }) rs-			, getInfo = return [("directory", dir)]+			, getInfo = return [("directory", dir')] 			, claimUrl = Nothing 			, checkUrl = Nothing 			, remoteStateHandle = rs 			}   where-	dir = fromMaybe (giveup "missing directory") $ remoteAnnexDirectory gc+	dir = toRawFilePath dir'+	dir' = fromMaybe (giveup "missing directory") (remoteAnnexDirectory gc)  directorySetup :: SetupStage -> Maybe UUID -> Maybe CredPair -> RemoteConfig -> RemoteGitConfig -> Annex (RemoteConfig, UUID) directorySetup _ mu _ c gc = do@@ -127,7 +132,7 @@ 	-- verify configuration is sane 	let dir = maybe (giveup "Specify directory=") fromProposedAccepted $ 		M.lookup directoryField c-	absdir <- liftIO $ absPath dir+	absdir <- liftIO $ fromRawFilePath <$> absPath (toRawFilePath dir) 	liftIO $ unlessM (doesDirectoryExist absdir) $ 		giveup $ "Directory does not exist: " ++ absdir 	(c', _encsetup) <- encryptionSetup c gc@@ -140,81 +145,90 @@ {- Locations to try to access a given Key in the directory.  - We try more than one since we used to write to different hash  - directories. -}-locations :: FilePath -> Key -> [FilePath]-locations d k = map (\f -> d </> fromRawFilePath f) (keyPaths k)+locations :: RawFilePath -> Key -> [RawFilePath]+locations d k = map (d P.</>) (keyPaths k)  {- Returns the location off a Key in the directory. If the key is  - present, returns the location that is actually used, otherwise  - returns the first, default location. -}-getLocation :: FilePath -> Key -> IO FilePath+getLocation :: RawFilePath -> Key -> IO RawFilePath getLocation d k = do 	let locs = locations d k-	fromMaybe (Prelude.head locs) <$> firstM doesFileExist locs+	fromMaybe (Prelude.head locs)+		<$> firstM (doesFileExist . fromRawFilePath) locs  {- Directory where the file(s) for a key are stored. -}-storeDir :: FilePath -> Key -> FilePath-storeDir d k = addTrailingPathSeparator $-	d </> fromRawFilePath (hashDirLower def k) </> fromRawFilePath (keyFile k)+storeDir :: RawFilePath -> Key -> RawFilePath+storeDir d k = P.addTrailingPathSeparator $+	d P.</> hashDirLower def k P.</> keyFile k  {- Check if there is enough free disk space in the remote's directory to  - store the key. Note that the unencrypted key size is checked. -}-storeKeyM :: FilePath -> ChunkConfig -> Storer+storeKeyM :: RawFilePath -> ChunkConfig -> Storer storeKeyM d chunkconfig k c m =  	ifM (checkDiskSpaceDirectory d k) 		( byteStorer (store d chunkconfig) k c m 		, giveup "Not enough free disk space." 		) -checkDiskSpaceDirectory :: FilePath -> Key -> Annex Bool+checkDiskSpaceDirectory :: RawFilePath -> Key -> Annex Bool checkDiskSpaceDirectory d k = do 	annexdir <- fromRepo gitAnnexObjectDir 	samefilesystem <- liftIO $ catchDefaultIO False $  		(\a b -> deviceID a == deviceID b)-			<$> getFileStatus d-			<*> getFileStatus annexdir+			<$> R.getFileStatus d+			<*> R.getFileStatus annexdir 	checkDiskSpace (Just d) k 0 samefilesystem -store :: FilePath -> ChunkConfig -> Key -> L.ByteString -> MeterUpdate -> Annex ()+store :: RawFilePath -> ChunkConfig -> Key -> L.ByteString -> MeterUpdate -> Annex () store d chunkconfig k b p = liftIO $ do 	void $ tryIO $ createDirectoryUnder d tmpdir 	case chunkconfig of 		LegacyChunks chunksize -> -			Legacy.store d chunksize (finalizeStoreGeneric d) k b p tmpdir destdir+			Legacy.store+				(fromRawFilePath d)+				chunksize+				(finalizeStoreGeneric d)+				k b p+				(fromRawFilePath tmpdir)+				(fromRawFilePath destdir) 		_ -> do-			let tmpf = tmpdir </> kf-			meteredWriteFile p tmpf b+			let tmpf = tmpdir P.</> kf+			meteredWriteFile p (fromRawFilePath tmpf) b 			finalizeStoreGeneric d tmpdir destdir   where-	tmpdir = addTrailingPathSeparator $ d </> "tmp" </> kf-	kf = fromRawFilePath (keyFile k)+	tmpdir = P.addTrailingPathSeparator $ d P.</> "tmp" P.</> kf+	kf = keyFile k 	destdir = storeDir d k  {- Passed a temp directory that contains the files that should be placed  - in the dest directory, moves it into place. Anything already existing  - in the dest directory will be deleted. File permissions will be locked  - down. -}-finalizeStoreGeneric :: FilePath -> FilePath -> FilePath -> IO ()+finalizeStoreGeneric :: RawFilePath -> RawFilePath -> RawFilePath -> IO () finalizeStoreGeneric d tmp dest = do-	removeDirGeneric d dest+	removeDirGeneric (fromRawFilePath d) dest' 	createDirectoryUnder d (parentDir dest)-	renameDirectory tmp dest+	renameDirectory (fromRawFilePath tmp) dest' 	-- may fail on some filesystems 	void $ tryIO $ do-		mapM_ preventWrite =<< dirContents dest+		mapM_ (preventWrite . toRawFilePath) =<< dirContents dest' 		preventWrite dest+  where+	dest' = fromRawFilePath dest -retrieveKeyFileM :: FilePath -> ChunkConfig -> Retriever+retrieveKeyFileM :: RawFilePath -> ChunkConfig -> Retriever retrieveKeyFileM d (LegacyChunks _) = Legacy.retrieve locations d retrieveKeyFileM d _ = byteRetriever $ \k sink ->-	sink =<< liftIO (L.readFile =<< getLocation d k)+	sink =<< liftIO (L.readFile . fromRawFilePath =<< getLocation d k) -retrieveKeyFileCheapM :: FilePath -> ChunkConfig -> Maybe (Key -> AssociatedFile -> FilePath -> Annex ())+retrieveKeyFileCheapM :: RawFilePath -> ChunkConfig -> Maybe (Key -> AssociatedFile -> FilePath -> Annex ()) -- no cheap retrieval possible for chunks retrieveKeyFileCheapM _ (UnpaddedChunks _) = Nothing retrieveKeyFileCheapM _ (LegacyChunks _) = Nothing #ifndef mingw32_HOST_OS retrieveKeyFileCheapM d NoChunks = Just $ \k _af f -> liftIO $ do-	file <- absPath =<< getLocation d k+	file <- fromRawFilePath <$> (absPath =<< getLocation d k) 	ifM (doesFileExist file) 		( createSymbolicLink file f 		, giveup "content file not present in remote"@@ -223,8 +237,10 @@ retrieveKeyFileCheapM _ _ = Nothing #endif -removeKeyM :: FilePath -> Remover-removeKeyM d k = liftIO $ removeDirGeneric d (storeDir d k)+removeKeyM :: RawFilePath -> Remover+removeKeyM d k = liftIO $ removeDirGeneric+	(fromRawFilePath d)+	(fromRawFilePath (storeDir d k))  {- Removes the directory, which must be located under the topdir.  -@@ -238,7 +254,7 @@  -} removeDirGeneric :: FilePath -> FilePath -> IO () removeDirGeneric topdir dir = do-	void $ tryIO $ allowWrite dir+	void $ tryIO $ allowWrite (toRawFilePath dir) #ifdef mingw32_HOST_OS 	{- Windows needs the files inside the directory to be writable 	 - before it can delete them. -}@@ -250,85 +266,88 @@ 			unlessM (doesDirectoryExist topdir <&&> (not <$> doesDirectoryExist dir)) $ 				throwM e -checkPresentM :: FilePath -> ChunkConfig -> CheckPresent+checkPresentM :: RawFilePath -> ChunkConfig -> CheckPresent checkPresentM d (LegacyChunks _) k = Legacy.checkKey d locations k checkPresentM d _ k = checkPresentGeneric d (locations d k) -checkPresentGeneric :: FilePath -> [FilePath] -> Annex Bool+checkPresentGeneric :: RawFilePath -> [RawFilePath] -> Annex Bool checkPresentGeneric d ps = checkPresentGeneric' d $-	liftIO $ anyM doesFileExist ps+	liftIO $ anyM (doesFileExist . fromRawFilePath) ps -checkPresentGeneric' :: FilePath -> Annex Bool -> Annex Bool+checkPresentGeneric' :: RawFilePath -> Annex Bool -> Annex Bool checkPresentGeneric' d check = ifM check 	( return True-	, ifM (liftIO $ doesDirectoryExist d)+	, ifM (liftIO $ doesDirectoryExist (fromRawFilePath d)) 		( return False-		, giveup $ "directory " ++ d ++ " is not accessible"+		, giveup $ "directory " ++ fromRawFilePath d ++ " is not accessible" 		) 	) -storeExportM :: FilePath -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex ()+storeExportM :: RawFilePath -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex () storeExportM d src _k loc p = liftIO $ do-	createDirectoryUnder d (takeDirectory dest)+	createDirectoryUnder d (P.takeDirectory dest) 	-- Write via temp file so that checkPresentGeneric will not 	-- see it until it's fully stored.-	viaTmp (\tmp () -> withMeteredFile src p (L.writeFile tmp)) dest ()+	viaTmp go (fromRawFilePath dest) ()   where 	dest = exportPath d loc+	go tmp () = withMeteredFile src p (L.writeFile tmp) -retrieveExportM :: FilePath -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex ()+retrieveExportM :: RawFilePath -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex () retrieveExportM d _k loc dest p =  	liftIO $ withMeteredFile src p (L.writeFile dest)   where-	src = exportPath d loc+	src = fromRawFilePath $ exportPath d loc -removeExportM :: FilePath -> Key -> ExportLocation -> Annex ()+removeExportM :: RawFilePath -> Key -> ExportLocation -> Annex () removeExportM d _k loc = liftIO $ do-	nukeFile src+	removeWhenExistsWith removeLink src 	removeExportLocation d loc   where-	src = exportPath d loc+	src = fromRawFilePath $ exportPath d loc -checkPresentExportM :: FilePath -> Key -> ExportLocation -> Annex Bool+checkPresentExportM :: RawFilePath -> Key -> ExportLocation -> Annex Bool checkPresentExportM d _k loc = 	checkPresentGeneric d [exportPath d loc] -renameExportM :: FilePath -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())+renameExportM :: RawFilePath -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ()) renameExportM d _k oldloc newloc = liftIO $ do-	createDirectoryUnder d (takeDirectory dest)-	renameFile src dest+	createDirectoryUnder d (P.takeDirectory dest)+	renameFile (fromRawFilePath src) (fromRawFilePath dest) 	removeExportLocation d oldloc 	return (Just ())   where 	src = exportPath d oldloc 	dest = exportPath d newloc -exportPath :: FilePath -> ExportLocation -> FilePath-exportPath d loc = d </> fromRawFilePath (fromExportLocation loc)+exportPath :: RawFilePath -> ExportLocation -> RawFilePath+exportPath d loc = d P.</> fromExportLocation loc  {- Removes the ExportLocation's parent directory and its parents, so long as  - they're empty, up to but not including the topdir. -}-removeExportLocation :: FilePath -> ExportLocation -> IO ()+removeExportLocation :: RawFilePath -> ExportLocation -> IO () removeExportLocation topdir loc = -	go (Just $ takeDirectory $ fromRawFilePath $ fromExportLocation loc) (Right ())+	go (Just $ P.takeDirectory $ fromExportLocation loc) (Right ())   where 	go _ (Left _e) = return () 	go Nothing _ = return ()-	go (Just loc') _ = go (upFrom loc')-		=<< tryIO (removeDirectory $ exportPath topdir (mkExportLocation (toRawFilePath loc')))+	go (Just loc') _ = +		let p = fromRawFilePath $ exportPath topdir $+			mkExportLocation loc'+		in go (upFrom loc') =<< tryIO (removeDirectory p) -listImportableContentsM :: FilePath -> Annex (Maybe (ImportableContents (ContentIdentifier, ByteSize)))+listImportableContentsM :: RawFilePath -> Annex (Maybe (ImportableContents (ContentIdentifier, ByteSize))) listImportableContentsM dir = catchMaybeIO $ liftIO $ do-	l <- dirContentsRecursive dir-	l' <- mapM go l+	l <- dirContentsRecursive (fromRawFilePath dir)+	l' <- mapM (go . toRawFilePath) l 	return $ ImportableContents (catMaybes l') []   where 	go f = do-		st <- getFileStatus f+		st <- R.getFileStatus f 		mkContentIdentifier f st >>= \case 			Nothing -> return Nothing 			Just cid -> do-				relf <- toRawFilePath <$> relPathDirToFile dir f+				relf <- relPathDirToFile dir f 				sz <- getFileSize' f st 				return $ Just (mkImportLocation relf, (cid, sz)) @@ -340,7 +359,7 @@ -- result in extra work to re-import them. -- -- If the file is not a regular file, this will return Nothing.-mkContentIdentifier :: FilePath -> FileStatus -> IO (Maybe ContentIdentifier)+mkContentIdentifier :: RawFilePath -> FileStatus -> IO (Maybe ContentIdentifier) mkContentIdentifier f st = 	fmap (ContentIdentifier . encodeBS . showInodeCache) 		<$> toInodeCache noTSDelta f st@@ -350,33 +369,35 @@ 	| new == Just old = cont 	| otherwise = giveup "file content has changed" -importKeyM :: FilePath -> ExportLocation -> ContentIdentifier -> MeterUpdate -> Annex Key+importKeyM :: RawFilePath -> ExportLocation -> ContentIdentifier -> MeterUpdate -> Annex Key importKeyM dir loc cid p = do-	backend <- chooseBackend (fromRawFilePath f)+	backend <- chooseBackend f 	k <- fst <$> genKey ks p backend-	currcid <- liftIO $ mkContentIdentifier absf =<< getFileStatus absf+	currcid <- liftIO $ mkContentIdentifier absf+		=<< R.getFileStatus absf 	guardSameContentIdentifiers (return k) cid currcid   where 	f = fromExportLocation loc-	absf = dir </> fromRawFilePath f+	absf = dir P.</> f 	ks  = KeySource 		{ keyFilename = f-		, contentLocation = toRawFilePath absf+		, contentLocation = absf 		, inodeCache = Nothing 		} -retrieveExportWithContentIdentifierM :: FilePath -> ExportLocation -> ContentIdentifier -> FilePath -> Annex Key -> MeterUpdate -> Annex Key+retrieveExportWithContentIdentifierM :: RawFilePath -> ExportLocation -> ContentIdentifier -> FilePath -> Annex Key -> MeterUpdate -> Annex Key retrieveExportWithContentIdentifierM dir loc cid dest mkkey p =  	precheck $ docopy postcheck   where 	f = exportPath dir loc+	f' = fromRawFilePath f  	docopy cont = do #ifndef mingw32_HOST_OS 		let open = do 			-- Need a duplicate fd for the post check, since 			-- hGetContentsMetered closes its handle.-			fd <- openFd f ReadOnly Nothing defaultFileFlags+			fd <- openFd f' ReadOnly Nothing defaultFileFlags 			dupfd <- dup fd 			h <- fdToHandle fd 			return (h, dupfd)@@ -385,7 +406,7 @@ 			closeFd dupfd 		bracketIO open close $ \(h, dupfd) -> do #else-		let open = openBinaryFile f ReadMode+		let open = openBinaryFile f' ReadMode 		let close = hClose 		bracketIO open close $ \h -> do #endif@@ -401,7 +422,7 @@ 	-- content. 	precheck cont = guardSameContentIdentifiers cont cid 		=<< liftIO . mkContentIdentifier f-		=<< liftIO (getFileStatus f)+		=<< liftIO (R.getFileStatus f)  	-- Check after copy, in case the file was changed while it was 	-- being copied.@@ -429,15 +450,16 @@ #endif 		guardSameContentIdentifiers cont cid currcid -storeExportWithContentIdentifierM :: FilePath -> FilePath -> Key -> ExportLocation -> [ContentIdentifier] -> MeterUpdate -> Annex ContentIdentifier+storeExportWithContentIdentifierM :: RawFilePath -> FilePath -> Key -> ExportLocation -> [ContentIdentifier] -> MeterUpdate -> Annex ContentIdentifier storeExportWithContentIdentifierM dir src _k loc overwritablecids p = do-	liftIO $ createDirectoryUnder dir destdir+	liftIO $ createDirectoryUnder dir (toRawFilePath destdir) 	withTmpFileIn destdir template $ \tmpf tmph -> do+		let tmpf' = toRawFilePath tmpf 		liftIO $ withMeteredFile src p (L.hPut tmph) 		liftIO $ hFlush tmph 		liftIO $ hClose tmph-		resetAnnexFilePerm tmpf-		liftIO (getFileStatus tmpf) >>= liftIO . mkContentIdentifier tmpf >>= \case+		resetAnnexFilePerm tmpf'+		liftIO (getFileStatus tmpf) >>= liftIO . mkContentIdentifier tmpf' >>= \case 			Nothing -> giveup "unable to generate content identifier" 			Just newcid -> do 				checkExportContent dir loc@@ -446,17 +468,17 @@ 					(const $ liftIO $ rename tmpf dest) 				return newcid   where-	dest = exportPath dir loc+	dest = fromRawFilePath $ exportPath dir loc 	(destdir, base) = splitFileName dest 	template = relatedTemplate (base ++ ".tmp") -removeExportWithContentIdentifierM :: FilePath -> Key -> ExportLocation -> [ContentIdentifier] -> Annex ()+removeExportWithContentIdentifierM :: RawFilePath -> Key -> ExportLocation -> [ContentIdentifier] -> Annex () removeExportWithContentIdentifierM dir k loc removeablecids = 	checkExportContent dir loc removeablecids (giveup "unsafe to remove modified file") $ \case 		DoesNotExist -> return () 		KnownContentIdentifier -> removeExportM dir k loc -checkPresentExportWithContentIdentifierM :: FilePath -> Key -> ExportLocation -> [ContentIdentifier] -> Annex Bool+checkPresentExportWithContentIdentifierM :: RawFilePath -> Key -> ExportLocation -> [ContentIdentifier] -> Annex Bool checkPresentExportWithContentIdentifierM dir _k loc knowncids = 	checkPresentGeneric' dir $ 		checkExportContent dir loc knowncids (return False) $ \case@@ -480,9 +502,9 @@ -- -- So, it suffices to check if the destination file's current -- content is known, and immediately run the callback.-checkExportContent :: FilePath -> ExportLocation -> [ContentIdentifier] -> Annex a -> (CheckResult -> Annex a) -> Annex a+checkExportContent :: RawFilePath -> ExportLocation -> [ContentIdentifier] -> Annex a -> (CheckResult -> Annex a) -> Annex a checkExportContent dir loc knowncids unsafe callback = -	tryWhenExists (liftIO $ getFileStatus dest) >>= \case+	tryWhenExists (liftIO $ R.getFileStatus dest) >>= \case 		Just destst 			| not (isRegularFile destst) -> unsafe 			| otherwise -> catchDefaultIO Nothing (liftIO $ mkContentIdentifier dest destst) >>= \case
Remote/Directory/LegacyChunked.hs view
@@ -7,10 +7,13 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Remote.Directory.LegacyChunked where  import qualified Data.ByteString.Lazy as L import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P  import Annex.Common import Utility.FileMode@@ -18,6 +21,7 @@ import qualified Remote.Helper.Chunked.Legacy as Legacy import Annex.Tmp import Utility.Metered+import Utility.Directory.Create  withCheckedFiles :: (FilePath -> IO Bool) -> FilePath -> (FilePath -> Key -> [FilePath]) -> Key -> ([FilePath] -> IO Bool) -> IO Bool withCheckedFiles _ [] _locations _ _ = return False@@ -70,17 +74,20 @@ 				feed bytes' (sz - s) ls h 			else return (l:ls) -storeHelper :: FilePath -> (FilePath -> FilePath -> IO ()) -> Key -> ([FilePath] -> IO [FilePath]) -> FilePath -> FilePath -> IO ()+storeHelper :: FilePath -> (RawFilePath -> RawFilePath -> IO ()) -> Key -> ([FilePath] -> IO [FilePath]) -> FilePath -> FilePath -> IO () storeHelper repotop finalizer key storer tmpdir destdir = do-	void $ liftIO $ tryIO $ createDirectoryUnder repotop tmpdir-	Legacy.storeChunks key tmpdir destdir storer recorder finalizer+	void $ liftIO $ tryIO $ createDirectoryUnder+		(toRawFilePath repotop)+		(toRawFilePath tmpdir)+	Legacy.storeChunks key tmpdir destdir storer recorder (legacyFinalizer finalizer)   where 	recorder f s = do-		void $ tryIO $ allowWrite f+		let f' = toRawFilePath f+		void $ tryIO $ allowWrite f' 		writeFile f s-		void $ tryIO $ preventWrite f+		void $ tryIO $ preventWrite f' -store :: FilePath -> ChunkSize -> (FilePath -> FilePath -> IO ()) -> Key -> L.ByteString -> MeterUpdate -> FilePath -> FilePath -> IO ()+store :: FilePath -> ChunkSize -> (RawFilePath -> RawFilePath -> IO ()) -> Key -> L.ByteString -> MeterUpdate -> FilePath -> FilePath -> IO () store repotop chunksize finalizer k b p = storeHelper repotop finalizer k $ \dests -> 	storeLegacyChunked p chunksize dests b @@ -88,21 +95,30 @@  - Done very innefficiently, by writing to a temp file.  - :/ This is legacy code..  -}-retrieve :: (FilePath -> Key -> [FilePath]) -> FilePath -> Retriever+retrieve :: (RawFilePath -> Key -> [RawFilePath]) -> RawFilePath -> Retriever retrieve locations d basek p c = withOtherTmp $ \tmpdir -> do 	showLongNote "This remote uses the deprecated chunksize setting. So this will be quite slow."-	let tmp = tmpdir </> fromRawFilePath (keyFile basek) ++ ".directorylegacy.tmp"+	let tmp = fromRawFilePath $ +		tmpdir P.</> keyFile basek <> ".directorylegacy.tmp" 	let go = \k sink -> do-		liftIO $ void $ withStoredFiles d locations k $ \fs -> do+		liftIO $ void $ withStoredFiles (fromRawFilePath d) (legacyLocations locations) k $ \fs -> do 			forM_ fs $ 				S.appendFile tmp <=< S.readFile 			return True 		b <- liftIO $ L.readFile tmp-		liftIO $ nukeFile tmp+		liftIO $ removeWhenExistsWith removeLink tmp 		sink b 	byteRetriever go basek p c -checkKey :: FilePath -> (FilePath -> Key -> [FilePath]) -> Key -> Annex Bool-checkKey d locations k = liftIO $ withStoredFiles d locations k $-	-- withStoredFiles checked that it exists-	const $ return True+checkKey :: RawFilePath -> (RawFilePath -> Key -> [RawFilePath]) -> Key -> Annex Bool+checkKey d locations k = liftIO $+	withStoredFiles (fromRawFilePath d) (legacyLocations locations) k $+		-- withStoredFiles checked that it exists+		const $ return True++legacyFinalizer :: (RawFilePath -> RawFilePath -> IO ()) -> (FilePath -> FilePath -> IO ())+legacyFinalizer f = \a b -> f (toRawFilePath a) (toRawFilePath b)++legacyLocations :: (RawFilePath -> Key -> [RawFilePath]) -> (FilePath -> Key -> [FilePath])+legacyLocations locations = \f k ->+	map fromRawFilePath $ locations (toRawFilePath f) k
Remote/GCrypt.hs view
@@ -1,6 +1,6 @@ {- git remotes encrypted using git-remote-gcrypt  -- - Copyright 2013 Joey Hess <id@joeyh.name>+ - Copyright 2013-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -20,6 +20,7 @@ import qualified Data.Map as M import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L+import qualified System.FilePath.ByteString as P import Control.Exception import Data.Default @@ -58,6 +59,7 @@ import Utility.Gpg import Utility.SshHost import Utility.Tuple+import Utility.Directory.Create import Messages.Progress import Types.ProposedAccepted @@ -284,7 +286,7 @@ 	 - which is needed for direct rsync of objects to work. 	 -} 	rsyncsetup = Remote.Rsync.withRsyncScratchDir $ \tmp -> do-		createAnnexDirectory (tmp </> objectDir)+		createAnnexDirectory (toRawFilePath (tmp </> objectDir)) 		dummycfg <- liftIO dummyRemoteGitConfig 		(rsynctransport, rsyncurl, _) <- rsyncTransport r dummycfg 		let tmpconfig = tmp </> "config"@@ -368,12 +370,12 @@ store' repo r rsyncopts 	| not $ Git.repoIsUrl repo =  		byteStorer $ \k b p -> guardUsable repo (giveup "cannot access remote") $ liftIO $ do-			let tmpdir = Git.repoLocation repo </> "tmp" </> fromRawFilePath (keyFile k)-			void $ tryIO $ createDirectoryUnder (Git.repoLocation repo) tmpdir-			let tmpf = tmpdir </> fromRawFilePath (keyFile k)-			meteredWriteFile p tmpf b-			let destdir = parentDir $ gCryptLocation repo k-			Remote.Directory.finalizeStoreGeneric (Git.repoLocation repo) tmpdir destdir+			let tmpdir = Git.repoPath repo P.</> "tmp" P.</> keyFile k+			void $ tryIO $ createDirectoryUnder (Git.repoPath repo) tmpdir+			let tmpf = tmpdir P.</> keyFile k+			meteredWriteFile p (fromRawFilePath tmpf) b+			let destdir = parentDir $ toRawFilePath $ gCryptLocation repo k+			Remote.Directory.finalizeStoreGeneric (Git.repoPath repo) tmpdir destdir 	| Git.repoIsSsh repo = if accessShell r 		then fileStorer $ \k f p -> do 			oh <- mkOutputHandler@@ -414,7 +416,9 @@ remove' :: Git.Repo -> Remote -> Remote.Rsync.RsyncOpts -> Remover remove' repo r rsyncopts k 	| not $ Git.repoIsUrl repo = guardUsable repo (giveup "cannot access remote") $-		liftIO $ Remote.Directory.removeDirGeneric (Git.repoLocation repo) (parentDir (gCryptLocation repo k))+		liftIO $ Remote.Directory.removeDirGeneric+			(fromRawFilePath (Git.repoPath repo))+			(fromRawFilePath (parentDir (toRawFilePath (gCryptLocation repo k)))) 	| Git.repoIsSsh repo = shellOrRsync r removeshell removersync 	| otherwise = unsupportedUrl   where
Remote/Git.hs view
@@ -640,8 +640,8 @@ 		loc <- liftIO $ gitAnnexLocation key repo gc 		liftIO $ ifM (R.doesPathExist loc) 			( do-				absloc <- absPath (fromRawFilePath loc)-				createSymbolicLink absloc file+				absloc <- absPath loc+				R.createSymbolicLink absloc (toRawFilePath file) 			, giveup "remote does not contain key" 			) 	| Git.repoIsSsh repo = Just $ \key af file ->@@ -692,7 +692,7 @@ 				let rsp = RetrievalAllKeysSecure 				res <- Annex.Content.getViaTmp rsp verify key $ \dest -> 					metered (Just (combineMeterUpdate meterupdate p)) key $ \_ p' -> -						copier object dest p' (liftIO checksuccessio)+						copier object (fromRawFilePath dest) p' (liftIO checksuccessio) 				Annex.Content.saveState True 				return res 			)@@ -820,7 +820,7 @@ 		State _ _ (CopyCoWTried v) _ _ -> v 	dorsync = do 		-- dest may already exist, so make sure rsync can write to it-		void $ liftIO $ tryIO $ allowWrite dest+		void $ liftIO $ tryIO $ allowWrite (toRawFilePath dest) 		oh <- mkOutputHandlerQuiet 		Ssh.rsyncHelper oh (Just p) $ 			rsyncparams ++ [File src, File dest]
Remote/GitLFS.hs view
@@ -389,7 +389,7 @@ 		ret sha256 size 	_ -> do 		sha256 <- calcsha256-		size <- liftIO $ getFileSize content+		size <- liftIO $ getFileSize (toRawFilePath content) 		rememberboth sha256 size 		ret sha256 size   where
Remote/Helper/Chunked.hs view
@@ -251,7 +251,7 @@   where 	go pe cks = do 		let ls = map chunkKeyList cks-		currsize <- liftIO $ catchMaybeIO $ getFileSize dest+		currsize <- liftIO $ catchMaybeIO $ getFileSize (toRawFilePath dest) 		let ls' = maybe ls (setupResume ls) currsize 		if any null ls' 			then noop -- dest is already complete
Remote/Helper/Hooks.hs view
@@ -5,11 +5,13 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}  module Remote.Helper.Hooks (addHooks) where  import qualified Data.Map as M+import qualified System.FilePath.ByteString as P  import Annex.Common import Types.Remote@@ -46,13 +48,13 @@ runHooks :: Remote -> Maybe String -> Maybe String -> Annex a -> Annex a runHooks r starthook stophook a = do 	dir <- fromRepo gitAnnexRemotesDir-	let lck = dir </> remoteid ++ ".lck"+	let lck = dir P.</> remoteid <> ".lck" 	whenM (notElem lck . M.keys <$> getLockCache) $ do 		createAnnexDirectory dir 		firstrun lck 	a   where-	remoteid = show (uuid r)+	remoteid = fromUUID (uuid r) 	run Nothing = noop 	run (Just command) = void $ liftIO $ 		boolSystem "sh" [Param "-c", Param command]
Remote/Helper/Http.hs view
@@ -32,7 +32,7 @@ -- the meter as it's sent. httpBodyStorer :: FilePath -> MeterUpdate -> IO RequestBody httpBodyStorer src m = do-	size <- getFileSize src+	size <- getFileSize (toRawFilePath src) 	let streamer sink = withMeteredFile src m $ \b -> byteStringPopper b sink 	return $ RequestBodyStream (fromInteger size) streamer 
Remote/Helper/P2P.hs view
@@ -32,7 +32,7 @@  store :: (MeterUpdate -> ProtoRunner Bool) -> Key -> AssociatedFile -> MeterUpdate -> Annex () store runner k af p = do-	let sizer = KeySizer k (fmap fst <$> prepSendAnnex k)+	let sizer = KeySizer k (fmap (toRawFilePath . fst) <$> prepSendAnnex k) 	metered (Just p) sizer $ \_ p' -> 		runner p' (P2P.put k af p') >>= \case 			Just True -> return ()
Remote/Helper/Special.hs view
@@ -93,8 +93,9 @@ fileStorer :: (Key -> FilePath -> MeterUpdate -> Annex ()) -> Storer fileStorer a k (FileContent f) m = a k f m fileStorer a k (ByteContent b) m = withTmp k $ \f -> do-	liftIO $ L.writeFile f b-	a k f m+	let f' = fromRawFilePath f+	liftIO $ L.writeFile f' b+	a k f' m  -- A Storer that expects to be provided with a L.ByteString of -- the content to store.@@ -106,8 +107,8 @@ fileRetriever :: (FilePath -> Key -> MeterUpdate -> Annex ()) -> Retriever fileRetriever a k m callback = do 	f <- prepTmp k-	a f k m-	pruneTmpWorkDirBefore f (callback . FileContent)+	a (fromRawFilePath f) k m+	pruneTmpWorkDirBefore f (callback . FileContent . fromRawFilePath)  -- A Retriever that generates a lazy ByteString containing the Key's -- content, and passes it to a callback action which will fully consume it@@ -248,7 +249,7 @@  	displayprogress p k srcfile a 		| displayProgress cfg =-			metered (Just p) (KeySizer k (return srcfile)) (const a)+			metered (Just p) (KeySizer k (pure (fmap toRawFilePath srcfile))) (const a) 		| otherwise = a p  {- Sink callback for retrieveChunks. Stores the file content into the@@ -283,10 +284,10 @@ 		withBytes content $ \b -> 			decrypt cmd c cipher (feedBytes b) $ 				readBytes write-		liftIO $ nukeFile f+		liftIO $ removeWhenExistsWith removeLink f 	(Nothing, _, FileContent f) -> do 		withBytes content write-		liftIO $ nukeFile f+		liftIO $ removeWhenExistsWith removeLink f 	(Nothing, _, ByteContent b) -> write b   where 	write b = case mh of
Remote/Rsync.hs view
@@ -224,7 +224,7 @@ storeGeneric' :: RsyncOpts -> MeterUpdate -> FilePath -> (FilePath -> Annex Bool) -> Annex Bool storeGeneric' o meterupdate basedest populatedest = withRsyncScratchDir $ \tmp -> do 	let dest = tmp </> basedest-	createAnnexDirectory (parentDir dest)+	createAnnexDirectory (parentDir (toRawFilePath dest)) 	ok <- populatedest dest 	ps <- sendParams 	if ok@@ -250,7 +250,7 @@   where 	includes = concatMap use dirHashes 	use h = let dir = fromRawFilePath (h def k) in-		[ parentDir dir+		[ fromRawFilePath (parentDir (toRawFilePath dir)) 		, dir 		-- match content directory and anything in it 		, dir </> fromRawFilePath (keyFile k) </> "***"@@ -314,7 +314,8 @@  removeExportM :: RsyncOpts -> Key -> ExportLocation -> Annex () removeExportM o _k loc =-	removeGeneric o $ includes $ fromRawFilePath $ fromExportLocation loc+	removeGeneric o $ map fromRawFilePath $+		includes $ fromExportLocation loc   where 	includes f = f : case upFrom f of 		Nothing -> []@@ -325,9 +326,9 @@   where 	d = fromRawFilePath $ fromExportDirectory ed 	allbelow f = f </> "***"-	includes f = f : case upFrom f of+	includes f = f : case upFrom (toRawFilePath f) of 		Nothing -> []-		Just f' -> includes f'+		Just f' -> includes (fromRawFilePath f')  renameExportM :: RsyncOpts -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ()) renameExportM _ _ _ _ = return Nothing@@ -351,7 +352,7 @@  - up trees for rsync. -} withRsyncScratchDir :: (FilePath -> Annex a) -> Annex a withRsyncScratchDir a = do-	t <- fromRepo gitAnnexTmpObjectDir+	t <- fromRawFilePath <$> fromRepo gitAnnexTmpObjectDir 	withTmpDirIn t "rsynctmp" a  rsyncRetrieve :: RsyncOpts -> [RsyncUrl] -> FilePath -> Maybe MeterUpdate -> Annex ()
Remote/Rsync/RsyncUrl.hs view
@@ -13,6 +13,7 @@ import Annex.Locations import Utility.Rsync import Utility.SafeCommand+import Utility.ShellEscape import Utility.FileSystemEncoding import Annex.DirHashes #ifdef mingw32_HOST_OS
Remote/S3.hs view
@@ -333,7 +333,7 @@ storeHelper :: S3Info -> S3Handle -> Maybe Magic -> FilePath -> S3.Object -> MeterUpdate -> Annex (Maybe S3Etag, Maybe S3VersionID) storeHelper info h magic f object p = liftIO $ case partSize info of 	Just partsz | partsz > 0 -> do-		fsz <- getFileSize f+		fsz <- getFileSize (toRawFilePath f) 		if fsz > partsz 			then multipartupload fsz partsz 			else singlepartupload
Remote/Tahoe.hs view
@@ -190,7 +190,8 @@  createClient :: TahoeConfigDir -> IntroducerFurl -> IO Bool createClient configdir furl = do-	createDirectoryIfMissing True (parentDir configdir)+	createDirectoryIfMissing True $+		fromRawFilePath $ parentDir $ toRawFilePath configdir 	boolTahoe configdir "create-client" 		[ Param "--nickname", Param "git-annex" 		, Param "--introducer", Param furl
Test.hs view
@@ -30,7 +30,8 @@ import Common import CmdLine.GitAnnex.Options -import qualified Utility.SafeCommand+import qualified Utility.ShellEscape+import qualified Utility.RawFilePath as R import qualified Annex import qualified Git.Filename import qualified Git.Types@@ -68,7 +69,7 @@ import qualified Annex.View.ViewedFile import qualified Logs.View import qualified Command.TestRemote-import qualified Utility.Path+import qualified Utility.Path.Tests import qualified Utility.FileMode import qualified BuildInfo import qualified Utility.Format@@ -141,7 +142,7 @@ 		exitWith exitcode 	runsubprocesstests (Just _) = isolateGitConfig $ do 		ensuretmpdir-		crippledfilesystem <- fst <$> Annex.Init.probeCrippledFileSystem' tmpdir+		crippledfilesystem <- fst <$> Annex.Init.probeCrippledFileSystem' (toRawFilePath tmpdir) 		adjustedbranchok <- Annex.AdjustedBranch.isGitVersionSupported 		case tryIngredients ingredients (tastyOptionSet opts) (tests crippledfilesystem adjustedbranchok opts) of 			Nothing -> error "No tests found!?"@@ -183,13 +184,13 @@ 	[ testProperty "prop_encode_decode_roundtrip" Git.Filename.prop_encode_decode_roundtrip 	, testProperty "prop_encode_c_decode_c_roundtrip" Utility.Format.prop_encode_c_decode_c_roundtrip 	, testProperty "prop_isomorphic_key_encode" Key.prop_isomorphic_key_encode-	, testProperty "prop_isomorphic_shellEscape" Utility.SafeCommand.prop_isomorphic_shellEscape-	, testProperty "prop_isomorphic_shellEscape_multiword" Utility.SafeCommand.prop_isomorphic_shellEscape_multiword+	, testProperty "prop_isomorphic_shellEscape" Utility.ShellEscape.prop_isomorphic_shellEscape+	, testProperty "prop_isomorphic_shellEscape_multiword" Utility.ShellEscape.prop_isomorphic_shellEscape_multiword 	, testProperty "prop_isomorphic_configEscape" Logs.Remote.prop_isomorphic_configEscape 	, testProperty "prop_parse_show_Config" Logs.Remote.prop_parse_show_Config-	, testProperty "prop_upFrom_basics" Utility.Path.prop_upFrom_basics-	, testProperty "prop_relPathDirToFile_basics" Utility.Path.prop_relPathDirToFile_basics-	, testProperty "prop_relPathDirToFile_regressionTest" Utility.Path.prop_relPathDirToFile_regressionTest+	, testProperty "prop_upFrom_basics" Utility.Path.Tests.prop_upFrom_basics+	, testProperty "prop_relPathDirToFileAbs_basics" Utility.Path.Tests.prop_relPathDirToFileAbs_basics+	, testProperty "prop_relPathDirToFileAbs_regressionTest" Utility.Path.Tests.prop_relPathDirToFileAbs_regressionTest 	, testProperty "prop_cost_sane" Config.Cost.prop_cost_sane 	, testProperty "prop_matcher_sane" Utility.Matcher.prop_matcher_sane 	, testProperty "prop_HmacSha1WithCipher_sane" Crypto.prop_HmacSha1WithCipher_sane@@ -311,6 +312,7 @@ 	, testCase "get (ssh remote)" test_get_ssh_remote 	, testCase "move" test_move 	, testCase "move (ssh remote)" test_move_ssh_remote+	, testCase "move (numcopies)" test_move_numcopies 	, testCase "copy" test_copy 	, testCase "lock" test_lock 	, testCase "lock --force" test_lock_force@@ -410,7 +412,7 @@ test_ignore_deleted_files = intmpclonerepo $ do 	git_annex "get" [annexedfile] @? "get failed" 	git_annex_expectoutput "find" [] [annexedfile]-	nukeFile annexedfile+	removeWhenExistsWith removeLink annexedfile 	-- A file that has been deleted, but the deletion not staged, 	-- is a special case; make sure git-annex skips these. 	git_annex_expectoutput "find" [] []@@ -656,6 +658,20 @@ 	unannexed ingitfile 	inmainrepo $ unannexed ingitfile +test_move_numcopies :: Assertion+test_move_numcopies = intmpclonerepo $ do+	inmainrepo $ annexed_present annexedfile+	git_annex "numcopies" ["2"] @? "setting numcopies failed"+	git_annex "move" ["--from", "origin", annexedfile] @? "move of file --from remote with numcopies unsatisfied but not made worse failed unexpectedly"+	annexed_present annexedfile+	inmainrepo $ annexed_notpresent annexedfile+	git_annex "move" ["--to", "origin", annexedfile] @? "move of file --to remote with numcopies unsatisfied but not made worse failed unexpectedly"+	annexed_notpresent annexedfile+	inmainrepo $ annexed_present annexedfile+	git_annex "get" [annexedfile] @? "get of file failed"+	git_annex_shouldfail "move" ["--from", "origin", annexedfile] @? "move of file --from remote violated numcopies setting"+	git_annex_shouldfail "move" ["--to", "origin", annexedfile] @? "move of file --to remote violated numcopies setting"+ test_copy :: Assertion test_copy = intmpclonerepo $ do 	annexed_notpresent annexedfile@@ -768,7 +784,8 @@ 		Just k <- Annex.WorkTree.lookupKey (toRawFilePath annexedfile) 		Database.Keys.removeInodeCaches k 		Database.Keys.closeDb-		liftIO . nukeFile =<< Annex.fromRepo Annex.Locations.gitAnnexKeysDbIndexCache+		liftIO . removeWhenExistsWith R.removeLink+			=<< Annex.fromRepo Annex.Locations.gitAnnexKeysDbIndexCache 	writecontent annexedfile "test_lock_force content" 	git_annex_shouldfail "lock" [annexedfile] @? "lock of modified file failed to fail" 	git_annex "lock" ["--force", annexedfile] @? "lock --force of modified file failed"@@ -866,7 +883,7 @@   where 	corrupt f = do 		git_annex "get" [f] @? "get of file failed"-		Utility.FileMode.allowWrite f+		Utility.FileMode.allowWrite (toRawFilePath f) 		writecontent f (changedcontent f) 		ifM (hasUnlockedFiles <$> getTestMode) 			( git_annex "fsck" [] @? "fsck failed on unlocked file with changed file content"@@ -1030,7 +1047,7 @@   where 	checkunused expectedkeys desc = do 		git_annex "unused" [] @? "unused failed"-		unusedmap <- annexeval $ Logs.Unused.readUnusedMap ""+		unusedmap <- annexeval $ Logs.Unused.readUnusedMap mempty 		let unusedkeys = M.elems unusedmap 		assertEqual ("unused keys differ " ++ desc) 			(sort expectedkeys) (sort unusedkeys)@@ -1315,7 +1332,7 @@ 					@? "unlock conflictor failed" 				writecontent conflictor "newconflictor" 			indir r1 $-				nukeFile conflictor+				removeWhenExistsWith removeLink conflictor 			let l = if inr1 then [r1, r2, r1] else [r2, r1, r2] 			forM_ l $ \r -> indir r $ 				git_annex "sync" [] @? "sync failed"@@ -1441,7 +1458,7 @@ 		withtmpclonerepo $ \r2 -> do 			indir r1 $ do 				disconnectOrigin-				createDirectoryIfMissing True (parentDir remoteconflictor)+				createDirectoryIfMissing True (fromRawFilePath (parentDir (toRawFilePath remoteconflictor))) 				writecontent remoteconflictor annexedcontent 				add_annex conflictor @? "add remoteconflicter failed" 				git_annex "sync" [] @? "sync failed in r1"@@ -1689,7 +1706,8 @@  test_bup_remote :: Assertion test_bup_remote = intmpclonerepo $ when BuildInfo.bup $ do-	dir <- absPath "dir" -- bup special remote needs an absolute path+	-- bup special remote needs an absolute path+	dir <- fromRawFilePath <$> absPath (toRawFilePath "dir") 	createDirectory dir 	git_annex "initremote" (words $ "foo type=bup encryption=none buprepo="++dir) @? "initremote failed" 	git_annex "get" [annexedfile] @? "get of file failed"@@ -1713,10 +1731,11 @@   where 	gpgcmd = Utility.Gpg.mkGpgCmd Nothing 	testscheme scheme = do-		abstmp <- absPath tmpdir+		abstmp <- fromRawFilePath <$> absPath (toRawFilePath tmpdir) 		testscheme' scheme abstmp 	testscheme' scheme abstmp = intmpclonerepo $ do-		gpgtmp <- (</> "gpgtmp") <$> relPathCwdToFile abstmp+		gpgtmp <- (</> "gpgtmp") . fromRawFilePath+			<$> relPathCwdToFile (toRawFilePath abstmp) 		createDirectoryIfMissing False gpgtmp 		Utility.Gpg.testTestHarness gpgtmp gpgcmd 			@? "test harness self-test failed"@@ -1813,7 +1832,7 @@ test_addurl = intmpclonerepo $ do 	-- file:// only; this test suite should not hit the network 	let filecmd c ps = git_annex c ("-cannex.security.allowed-url-schemes=file" : ps)-	f <- absPath "myurl"+	f <- fromRawFilePath <$> absPath (toRawFilePath "myurl") 	let url = replace "\\" "/" ("file:///" ++ dropDrive f) 	writecontent f "foo" 	git_annex_shouldfail "addurl" [url] @? "addurl failed to fail on file url"@@ -1842,7 +1861,7 @@ 	git_annex "merge" ["foo/" ++ origbranch] @? "git annex merge failed" 	annexed_present_imported "import" -	nukeFile "import"+	removeWhenExistsWith removeLink "import" 	writecontent "import" (content "newimport1") 	git_annex "add" ["import"] @? "add of import failed" 	commitchanges@@ -1851,7 +1870,7 @@  	-- verify that export refuses to overwrite modified file 	writedir "import" (content "newimport2")-	nukeFile "import"+	removeWhenExistsWith removeLink "import" 	writecontent "import" (content "newimport3") 	git_annex "add" ["import"] @? "add of import failed" 	commitchanges@@ -1861,7 +1880,7 @@ 	-- resolving import conflict 	git_annex "import" [origbranch, "--from", "foo"] @? "import from dir failed" 	not <$> boolSystem "git" [Param "merge", Param "foo/master", Param "-mmerge"] @? "git merge of conflict failed to exit nonzero"-	nukeFile "import"+	removeWhenExistsWith removeLink "import" 	writecontent "import" (content "newimport3") 	git_annex "add" ["import"] @? "add of import failed" 	commitchanges
Test/Framework.hs view
@@ -93,8 +93,9 @@ with_ssh_origin cloner a = cloner $ do 	let k = Git.Types.ConfigKey (encodeBS' config) 	let v = Git.Types.ConfigValue (toRawFilePath "/dev/null")-	origindir <- absPath . Git.Types.fromConfigValue =<< annexeval (Config.getConfig k v)-	let originurl = "localhost:" ++ origindir+	origindir <- absPath . Git.Types.fromConfigValue+		=<< annexeval (Config.getConfig k v)+	let originurl = "localhost:" ++ fromRawFilePath origindir 	boolSystem "git" [Param "config", Param config, Param originurl] @? "git config failed" 	a   where@@ -105,7 +106,7 @@  checkRepo :: Types.Annex a -> FilePath -> IO a checkRepo getval d = do-	s <- Annex.new =<< Git.Construct.fromPath d+	s <- Annex.new =<< Git.Construct.fromPath (toRawFilePath d) 	Annex.eval s $ 		getval `finally` Annex.Action.stopCoProcesses @@ -223,7 +224,7 @@ {- Prevent global git configs from affecting the test suite. -} isolateGitConfig :: IO a -> IO a isolateGitConfig a = Utility.Tmp.Dir.withTmpDir "testhome" $ \tmphome -> do-	tmphomeabs <- absPath tmphome+	tmphomeabs <- fromRawFilePath <$> absPath (toRawFilePath tmphome) 	Utility.Env.Set.setEnv "HOME" tmphomeabs True 	Utility.Env.Set.setEnv "XDG_CONFIG_HOME" tmphomeabs True 	Utility.Env.Set.setEnv "GIT_CONFIG_NOSYSTEM" "1" True
Types/Backend.hs view
@@ -20,7 +20,7 @@ 	, genKey :: Maybe (KeySource -> MeterUpdate -> a Key) 	-- Verifies the content of a key using a hash. This does not need 	-- to be cryptographically secure.-	, verifyKeyContent :: Maybe (Key -> FilePath -> a Bool)+	, verifyKeyContent :: Maybe (Key -> RawFilePath -> a Bool) 	-- Checks if a key can be upgraded to a better form. 	, canUpgradeKey :: Maybe (Key -> Bool) 	-- Checks if there is a fast way to migrate a key to a different
Types/LockCache.hs view
@@ -10,7 +10,9 @@ 	LockHandle ) where -import qualified Data.Map as M import Utility.LockPool (LockHandle) -type LockCache = M.Map FilePath LockHandle+import qualified Data.Map as M+import System.FilePath.ByteString (RawFilePath)++type LockCache = M.Map RawFilePath LockHandle
Types/Transfer.hs view
@@ -5,6 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE FlexibleInstances #-}  module Types.Transfer where@@ -17,6 +18,7 @@ import Utility.Url import Utility.FileSystemEncoding +import qualified Data.ByteString as B import Data.Time.Clock.POSIX import Control.Concurrent import Control.Applicative@@ -56,7 +58,7 @@ data Direction = Upload | Download 	deriving (Eq, Ord, Show, Read) -formatDirection :: Direction -> String+formatDirection :: Direction -> B.ByteString formatDirection Upload = "upload" formatDirection Download = "download" 
Upgrade.hs view
@@ -51,9 +51,9 @@   where 	err msg = do 		g <- Annex.gitRepo-		p <- liftIO $ absPath $ fromRawFilePath $ Git.repoPath g+		p <- liftIO $ absPath $ Git.repoPath g 		return $ Just $ unwords-			[ "Repository", p+			[ "Repository", fromRawFilePath p 			, "is at unsupported version" 			, show (fromRepoVersion v) ++ "." 			, msg
Upgrade/V0.hs view
@@ -18,7 +18,8 @@ 	-- do the reorganisation of the key files 	olddir <- fromRawFilePath <$> fromRepo gitAnnexDir 	keys <- getKeysPresent0 olddir-	forM_ keys $ \k -> moveAnnex k $ olddir </> keyFile0 k+	forM_ keys $ \k ->+		moveAnnex k $ toRawFilePath $ olddir </> keyFile0 k  	-- update the symlinks to the key files 	-- No longer needed here; V1.upgrade does the same thing
Upgrade/V1.hs view
@@ -13,6 +13,7 @@ import Data.ByteString.Builder import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L+import qualified System.FilePath.ByteString as P  import Annex.Common import Annex.Content@@ -74,12 +75,13 @@ 	forM_ files move   where 	move f = do-		let k = fileKey1 (takeFileName f)-		let d = parentDir f+		let f' = toRawFilePath f+		let k = fileKey1 (fromRawFilePath (P.takeFileName f'))+		let d = parentDir f' 		liftIO $ allowWrite d-		liftIO $ allowWrite f-		_ <- moveAnnex k f-		liftIO $ removeDirectory d+		liftIO $ allowWrite f'+		_ <- moveAnnex k f'+		liftIO $ removeDirectory (fromRawFilePath d)  updateSymlinks :: Annex () updateSymlinks = do@@ -94,7 +96,8 @@ 		case r of 			Nothing -> noop 			Just (k, _) -> do-				link <- calcRepo $ gitAnnexLink f k+				link <- fromRawFilePath+					<$> calcRepo (gitAnnexLink (toRawFilePath f) k) 				liftIO $ removeFile f 				liftIO $ createSymbolicLink link f 				Annex.Queue.addCommand "add" [Param "--"] [f]@@ -113,10 +116,10 @@ 			, return [] 			) 	move (l, k) = do-		dest <- fromRepo $ logFile2 k+		dest <- fromRepo (logFile2 k) 		dir <- fromRepo Upgrade.V2.gitStateDir 		let f = dir </> l-		createWorkTreeDirectory (parentDir dest)+		createWorkTreeDirectory (parentDir (toRawFilePath dest)) 		-- could just git mv, but this way deals with 		-- log files that are not checked into git, 		-- as well as merging with already upgraded@@ -214,7 +217,8 @@ 			" (unknown backend " ++ bname ++ ")"  getKeyFilesPresent1 :: Annex [FilePath]-getKeyFilesPresent1  = getKeyFilesPresent1' =<< fromRepo gitAnnexObjectDir+getKeyFilesPresent1  = getKeyFilesPresent1' . fromRawFilePath+	=<< fromRepo gitAnnexObjectDir getKeyFilesPresent1' :: FilePath -> Annex [FilePath] getKeyFilesPresent1' dir = 	ifM (liftIO $ doesDirectoryExist dir)
Upgrade/V2.hs view
@@ -132,7 +132,7 @@  gitAttributesUnWrite :: Git.Repo -> IO () gitAttributesUnWrite repo = do-	let attributes = Git.attributes repo+	let attributes = fromRawFilePath (Git.attributes repo) 	whenM (doesFileExist attributes) $ do 		c <- readFileStrict attributes 		liftIO $ viaTmp writeFile attributes $ unlines $
Upgrade/V5.hs view
@@ -132,13 +132,14 @@  	fromdirect f k = ifM (Direct.goodContent k f) 		( do+			let f' = toRawFilePath f 			-- If linkToAnnex fails for some reason, the work tree 			-- file still has the content; the annex object file 			-- is just not populated with it. Since the work tree 			-- file is recorded as an associated file, things will 			-- still work that way, it's just not ideal.-			ic <- withTSDelta (liftIO . genInodeCache (toRawFilePath f))-			void $ Content.linkToAnnex k f ic+			ic <- withTSDelta (liftIO . genInodeCache f')+			void $ Content.linkToAnnex k f' ic 		, unlessM (Content.inAnnex k) $ do 			-- Worktree file was deleted or modified; 			-- if there are no other copies of the content@@ -150,7 +151,7 @@ 		) 	 	writepointer f k = liftIO $ do-		nukeFile f+		removeWhenExistsWith removeLink f 		S.writeFile f (formatPointer k)  {- Remove all direct mode bookkeeping files. -}
Upgrade/V5/Direct.hs view
@@ -28,6 +28,7 @@ import Annex.Perms import Utility.InodeCache import Annex.InodeSentinal+import qualified Utility.RawFilePath as R  setIndirect :: Annex () setIndirect = do@@ -86,7 +87,7 @@  - the top of the repo. -} associatedFilesRelative :: Key -> Annex [FilePath]  associatedFilesRelative key = do-	mapping <- calcRepo $ gitAnnexMapping key+	mapping <- fromRawFilePath <$> calcRepo (gitAnnexMapping key) 	liftIO $ catchDefaultIO [] $ withFile mapping ReadMode $ \h -> 		-- Read strictly to ensure the file is closed promptly 		lines <$> hGetContentsStrict h@@ -96,7 +97,7 @@ removeAssociatedFiles key = do 	mapping <- calcRepo $ gitAnnexMapping key 	modifyContent mapping $-		liftIO $ nukeFile mapping+		liftIO $ removeWhenExistsWith R.removeLink mapping  {- Checks if a file in the tree, associated with a key, has not been modified.  -@@ -116,13 +117,27 @@ recordedInodeCache :: Key -> Annex [InodeCache] recordedInodeCache key = withInodeCacheFile key $ \f -> 	liftIO $ catchDefaultIO [] $-		mapMaybe readInodeCache . lines <$> readFileStrict f+		mapMaybe readInodeCache . lines+			<$> readFileStrict (fromRawFilePath f)  {- Removes an inode cache. -} removeInodeCache :: Key -> Annex () removeInodeCache key = withInodeCacheFile key $ \f -> 	modifyContent f $-		liftIO $ nukeFile f+		liftIO $ removeWhenExistsWith R.removeLink f -withInodeCacheFile :: Key -> (FilePath -> Annex a) -> Annex a+withInodeCacheFile :: Key -> (RawFilePath -> Annex a) -> Annex a withInodeCacheFile key a = a =<< calcRepo (gitAnnexInodeCache key)++{- File that maps from a key to the file(s) in the git repository. -}+gitAnnexMapping :: Key -> Git.Repo -> GitConfig -> IO RawFilePath+gitAnnexMapping key r c = do+	loc <- gitAnnexLocation key r c+	return $ loc <> ".map"++{- File that caches information about a key's content, used to determine+ - if a file has changed. -}+gitAnnexInodeCache :: Key -> Git.Repo -> GitConfig -> IO RawFilePath+gitAnnexInodeCache key r c = do+	loc <- gitAnnexLocation key r c+	return $ loc <> ".cache"
Upgrade/V7.hs view
@@ -5,6 +5,7 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-}  module Upgrade.V7 where@@ -18,7 +19,10 @@ import qualified Git import Git.FilePath import Config+import qualified Utility.RawFilePath as R +import qualified System.FilePath.ByteString as P+ upgrade :: Bool -> Annex Bool upgrade automatic = do 	unless automatic $@@ -33,7 +37,8 @@ 	-- new database is not populated. It will be automatically 	-- populated from the git-annex branch the next time it is used. 	removeOldDb gitAnnexContentIdentifierDbDirOld-	liftIO . nukeFile =<< fromRepo gitAnnexContentIdentifierLockOld+	liftIO . removeWhenExistsWith R.removeLink+		=<< fromRepo gitAnnexContentIdentifierLockOld  	-- The export databases are deleted here. The new databases 	-- will be populated by the next thing that needs them, the same@@ -42,31 +47,33 @@  	populateKeysDb 	removeOldDb gitAnnexKeysDbOld-	liftIO . nukeFile =<< fromRepo gitAnnexKeysDbIndexCacheOld-	liftIO . nukeFile =<< fromRepo gitAnnexKeysDbLockOld+	liftIO . removeWhenExistsWith R.removeLink+		=<< fromRepo gitAnnexKeysDbIndexCacheOld+	liftIO . removeWhenExistsWith R.removeLink+		=<< fromRepo gitAnnexKeysDbLockOld 	 	updateSmudgeFilter  	return True -gitAnnexKeysDbOld :: Git.Repo -> FilePath-gitAnnexKeysDbOld r = fromRawFilePath (gitAnnexDir r) </> "keys"+gitAnnexKeysDbOld :: Git.Repo -> RawFilePath+gitAnnexKeysDbOld r = gitAnnexDir r P.</> "keys" -gitAnnexKeysDbLockOld :: Git.Repo -> FilePath-gitAnnexKeysDbLockOld r = gitAnnexKeysDbOld r ++ ".lck"+gitAnnexKeysDbLockOld :: Git.Repo -> RawFilePath+gitAnnexKeysDbLockOld r = gitAnnexKeysDbOld r <> ".lck" -gitAnnexKeysDbIndexCacheOld :: Git.Repo -> FilePath-gitAnnexKeysDbIndexCacheOld r = gitAnnexKeysDbOld r ++ ".cache"+gitAnnexKeysDbIndexCacheOld :: Git.Repo -> RawFilePath+gitAnnexKeysDbIndexCacheOld r = gitAnnexKeysDbOld r <> ".cache" -gitAnnexContentIdentifierDbDirOld :: Git.Repo -> FilePath-gitAnnexContentIdentifierDbDirOld r = fromRawFilePath (gitAnnexDir r) </> "cids"+gitAnnexContentIdentifierDbDirOld :: Git.Repo -> RawFilePath+gitAnnexContentIdentifierDbDirOld r = gitAnnexDir r P.</> "cids" -gitAnnexContentIdentifierLockOld :: Git.Repo -> FilePath-gitAnnexContentIdentifierLockOld r = gitAnnexContentIdentifierDbDirOld r ++ ".lck"+gitAnnexContentIdentifierLockOld :: Git.Repo -> RawFilePath+gitAnnexContentIdentifierLockOld r = gitAnnexContentIdentifierDbDirOld r <> ".lck" -removeOldDb :: (Git.Repo -> FilePath) -> Annex ()+removeOldDb :: (Git.Repo -> RawFilePath) -> Annex () removeOldDb getdb = do-	db <- fromRepo getdb+	db <- fromRawFilePath <$> fromRepo getdb 	whenM (liftIO $ doesDirectoryExist db) $ do 		v <- liftIO $ tryNonAsync $ #if MIN_VERSION_directory(1,2,7)@@ -121,7 +128,7 @@ -- checked into the repository. updateSmudgeFilter :: Annex () updateSmudgeFilter = do-	lf <- Annex.fromRepo Git.attributesLocal+	lf <- fromRawFilePath <$> Annex.fromRepo Git.attributesLocal 	ls <- liftIO $ lines <$> catchDefaultIO "" (readFileStrict lf) 	let ls' = removedotfilter ls 	when (ls /= ls') $
Utility/Base64.hs view
@@ -8,6 +8,7 @@ module Utility.Base64 where  import Utility.FileSystemEncoding+import Utility.QuickCheck  import qualified "sandi" Codec.Binary.Base64 as B64 import Data.Maybe@@ -43,7 +44,9 @@ -- Only ascii strings are tested, because an arbitrary string may contain -- characters not encoded using the FileSystemEncoding, which would thus -- not roundtrip, as decodeBS always generates an output encoded that way.-prop_b64_roundtrips :: String -> Bool-prop_b64_roundtrips s+prop_b64_roundtrips :: TestableString -> Bool+prop_b64_roundtrips ts 	| all (isAscii) s = s == decodeBS (fromB64' (toB64' (encodeBS s))) 	| otherwise = True+  where+	s = fromTestableString ts
Utility/Directory.hs view
@@ -18,24 +18,14 @@ import System.FilePath import System.PosixCompat.Files import Control.Applicative-import Control.Monad.IO.Class-import Control.Monad.IfElse import System.IO.Unsafe (unsafeInterleaveIO)-import System.IO.Error import Data.Maybe import Prelude -#ifndef mingw32_HOST_OS-import Utility.SafeCommand-#endif- import Utility.SystemDirectory-import Utility.Path-import Utility.Tmp import Utility.Exception import Utility.Monad import Utility.Applicative-import Utility.PartialPrelude  dirCruft :: FilePath -> Bool dirCruft "." = True@@ -101,130 +91,9 @@ 				=<< catchDefaultIO [] (dirContents dir) 			go (subdirs++dir:c) dirs -{- Moves one filename to another.- - First tries a rename, but falls back to moving across devices if needed. -}-moveFile :: FilePath -> FilePath -> IO ()-moveFile src dest = tryIO (rename src dest) >>= onrename-  where-	onrename (Right _) = noop-	onrename (Left e)-		| isPermissionError e = rethrow-		| isDoesNotExistError e = rethrow-		| otherwise = viaTmp mv dest ()-	  where-		rethrow = throwM e--		mv tmp () = do-			-- copyFile is likely not as optimised as-			-- the mv command, so we'll use the command.-			---			-- But, while Windows has a "mv", it does not seem very-			-- reliable, so use copyFile there.-#ifndef mingw32_HOST_OS	-			-- If dest is a directory, mv would move the file-			-- into it, which is not desired.-			whenM (isdir dest) rethrow-			ok <- boolSystem "mv" [Param "-f", Param src, Param tmp]-			let e' = e-#else-			r <- tryIO $ copyFile src tmp-			let (ok, e') = case r of-				Left err -> (False, err)-				Right _ -> (True, e)-#endif-			unless ok $ do-				-- delete any partial-				_ <- tryIO $ removeFile tmp-				throwM e'--#ifndef mingw32_HOST_OS	-	isdir f = do-		r <- tryIO $ getFileStatus f-		case r of-			(Left _) -> return False-			(Right s) -> return $ isDirectory s-#endif--{- Removes a file (or symlink), which may or may not exist.- -- - Note that an exception is thrown if the file exists but- - cannot be removed, or if its a directory. -}-nukeFile :: FilePath -> IO ()-nukeFile file = void $ tryWhenExists go-  where-#ifndef mingw32_HOST_OS-	go = removeLink file-#else-	go = removeFile file-#endif--{- Like createDirectoryIfMissing True, but it will only create- - missing parent directories up to but not including the directory- - in the first parameter.- -- - For example, createDirectoryUnder "/tmp/foo" "/tmp/foo/bar/baz"- - will create /tmp/foo/bar if necessary, but if /tmp/foo does not exist,- - it will throw an exception.- -- - The exception thrown is the same that createDirectory throws if the- - parent directory does not exist.- -- - If the second FilePath is not under the first- - FilePath (or the same as it), it will fail with an exception- - even if the second FilePath's parent directory already exists.- -- - Either or both of the FilePaths can be relative, or absolute.- - They will be normalized as necessary.+{- Use with an action that removes something, which may or may not exist.  -- - Note that, the second FilePath, if relative, is relative to the current- - working directory, not to the first FilePath.+ - If an exception is thrown due to it not existing, it is ignored.  -}-createDirectoryUnder :: FilePath -> FilePath -> IO ()-createDirectoryUnder topdir dir =-	createDirectoryUnder' topdir dir createDirectory--createDirectoryUnder'-	:: (MonadIO m, MonadCatch m)-	=> FilePath-	-> FilePath-	-> (FilePath -> m ())-	-> m ()-createDirectoryUnder' topdir dir0 mkdir = do-	p <- liftIO $ relPathDirToFile topdir dir0-	let dirs = splitDirectories p-	-- Catch cases where the dir is not beneath the topdir.-	-- If the relative path between them starts with "..",-	-- it's not. And on Windows, if they are on different drives,-	-- the path will not be relative.-	if headMaybe dirs == Just ".." || isAbsolute p-		then liftIO $ ioError $ customerror userErrorType-			("createDirectoryFrom: not located in " ++ topdir)-		-- If dir0 is the same as the topdir, don't try to create-		-- it, but make sure it does exist.-		else if null dirs-			then liftIO $ unlessM (doesDirectoryExist topdir) $-				ioError $ customerror doesNotExistErrorType-					"createDirectoryFrom: does not exist"-			else createdirs $-				map (topdir </>) (reverse (scanl1 (</>) dirs))-  where-	customerror t s = mkIOError t s Nothing (Just dir0)--	createdirs [] = pure ()-	createdirs (dir:[]) = createdir dir (liftIO . ioError)-	createdirs (dir:dirs) = createdir dir $ \_ -> do-		createdirs dirs-		createdir dir (liftIO . ioError)--	-- This is the same method used by createDirectoryIfMissing,-	-- in particular the handling of errors that occur when the-	-- directory already exists. See its source for explanation-	-- of several subtleties.-	createdir dir notexisthandler = tryIO (mkdir dir) >>= \case-		Right () -> pure ()-		Left e-			| isDoesNotExistError e -> notexisthandler e-			| isAlreadyExistsError e || isPermissionError e ->-				liftIO $ unlessM (doesDirectoryExist dir) $-					ioError e-			| otherwise -> liftIO $ ioError e+removeWhenExistsWith :: (a -> IO ()) -> a -> IO ()+removeWhenExistsWith f a = void $ tryWhenExists $ f a
+ Utility/Directory/Create.hs view
@@ -0,0 +1,102 @@+{- directory creating+ -+ - Copyright 2011-2020 Joey Hess <id@joeyh.name>+ -+ - License: BSD-2-clause+ -}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}++module Utility.Directory.Create (+	createDirectoryUnder,+	createDirectoryUnder',+) where++import Control.Monad+import Control.Applicative+import Control.Monad.IO.Class+import Control.Monad.IfElse+import System.IO.Error+import Data.Maybe+import qualified System.FilePath.ByteString as P+import Prelude++import Utility.SystemDirectory+import Utility.Path.AbsRel+import Utility.Exception+import Utility.FileSystemEncoding+import qualified Utility.RawFilePath as R+import Utility.PartialPrelude++{- Like createDirectoryIfMissing True, but it will only create+ - missing parent directories up to but not including the directory+ - in the first parameter.+ -+ - For example, createDirectoryUnder "/tmp/foo" "/tmp/foo/bar/baz"+ - will create /tmp/foo/bar if necessary, but if /tmp/foo does not exist,+ - it will throw an exception.+ -+ - The exception thrown is the same that createDirectory throws if the+ - parent directory does not exist.+ -+ - If the second FilePath is not under the first+ - FilePath (or the same as it), it will fail with an exception+ - even if the second FilePath's parent directory already exists.+ -+ - Either or both of the FilePaths can be relative, or absolute.+ - They will be normalized as necessary.+ -+ - Note that, the second FilePath, if relative, is relative to the current+ - working directory, not to the first FilePath.+ -}+createDirectoryUnder :: RawFilePath -> RawFilePath -> IO ()+createDirectoryUnder topdir dir =+	createDirectoryUnder' topdir dir R.createDirectory++createDirectoryUnder'+	:: (MonadIO m, MonadCatch m)+	=> RawFilePath+	-> RawFilePath+	-> (RawFilePath -> m ())+	-> m ()+createDirectoryUnder' topdir dir0 mkdir = do+	p <- liftIO $ relPathDirToFile topdir dir0+	let dirs = P.splitDirectories p+	-- Catch cases where the dir is not beneath the topdir.+	-- If the relative path between them starts with "..",+	-- it's not. And on Windows, if they are on different drives,+	-- the path will not be relative.+	if headMaybe dirs == Just ".." || P.isAbsolute p+		then liftIO $ ioError $ customerror userErrorType+			("createDirectoryFrom: not located in " ++ fromRawFilePath topdir)+		-- If dir0 is the same as the topdir, don't try to create+		-- it, but make sure it does exist.+		else if null dirs+			then liftIO $ unlessM (doesDirectoryExist (fromRawFilePath topdir)) $+				ioError $ customerror doesNotExistErrorType+					"createDirectoryFrom: does not exist"+			else createdirs $+				map (topdir P.</>) (reverse (scanl1 (P.</>) dirs))+  where+	customerror t s = mkIOError t s Nothing (Just (fromRawFilePath dir0))++	createdirs [] = pure ()+	createdirs (dir:[]) = createdir dir (liftIO . ioError)+	createdirs (dir:dirs) = createdir dir $ \_ -> do+		createdirs dirs+		createdir dir (liftIO . ioError)++	-- This is the same method used by createDirectoryIfMissing,+	-- in particular the handling of errors that occur when the+	-- directory already exists. See its source for explanation+	-- of several subtleties.+	createdir dir notexisthandler = tryIO (mkdir dir) >>= \case+		Right () -> pure ()+		Left e+			| isDoesNotExistError e -> notexisthandler e+			| isAlreadyExistsError e || isPermissionError e ->+				liftIO $ unlessM (doesDirectoryExist (fromRawFilePath dir)) $+					ioError e+			| otherwise -> liftIO $ ioError e
Utility/DottedVersion.hs view
@@ -13,7 +13,7 @@ 	normalize, ) where -import Common+import Utility.Split  data DottedVersion = DottedVersion String Integer 	deriving (Eq)
Utility/FileMode.hs view
@@ -22,22 +22,24 @@ import Control.Monad.Catch  import Utility.Exception+import Utility.FileSystemEncoding+import qualified Utility.RawFilePath as R  {- Applies a conversion function to a file's mode. -}-modifyFileMode :: FilePath -> (FileMode -> FileMode) -> IO ()+modifyFileMode :: RawFilePath -> (FileMode -> FileMode) -> IO () modifyFileMode f convert = void $ modifyFileMode' f convert -modifyFileMode' :: FilePath -> (FileMode -> FileMode) -> IO FileMode+modifyFileMode' :: RawFilePath -> (FileMode -> FileMode) -> IO FileMode modifyFileMode' f convert = do-	s <- getFileStatus f+	s <- R.getFileStatus f 	let old = fileMode s 	let new = convert old 	when (new /= old) $-		setFileMode f new+		R.setFileMode f new 	return old  {- Runs an action after changing a file's mode, then restores the old mode. -}-withModifiedFileMode :: FilePath -> (FileMode -> FileMode) -> IO a -> IO a+withModifiedFileMode :: RawFilePath -> (FileMode -> FileMode) -> IO a -> IO a withModifiedFileMode file convert a = bracket setup cleanup go   where 	setup = modifyFileMode' file convert@@ -70,15 +72,15 @@ 	]  {- Removes the write bits from a file. -}-preventWrite :: FilePath -> IO ()+preventWrite :: RawFilePath -> IO () preventWrite f = modifyFileMode f $ removeModes writeModes  {- Turns a file's owner write bit back on. -}-allowWrite :: FilePath -> IO ()+allowWrite :: RawFilePath -> IO () allowWrite f = modifyFileMode f $ addModes [ownerWriteMode]  {- Turns a file's owner read bit back on. -}-allowRead :: FilePath -> IO ()+allowRead :: RawFilePath -> IO () allowRead f = modifyFileMode f $ addModes [ownerReadMode]  {- Allows owner and group to read and write to a file. -}@@ -88,7 +90,7 @@ 	, ownerReadMode, groupReadMode 	] -groupWriteRead :: FilePath -> IO ()+groupWriteRead :: RawFilePath -> IO () groupWriteRead f = modifyFileMode f $ addModes groupSharedModes  checkMode :: FileMode -> FileMode -> Bool@@ -149,7 +151,7 @@ stickyMode :: FileMode stickyMode = 512 -setSticky :: FilePath -> IO ()+setSticky :: RawFilePath -> IO () setSticky f = modifyFileMode f $ addModes [stickyMode] #endif @@ -162,13 +164,13 @@  - On a filesystem that does not support file permissions, this is the same  - as writeFile.  -}-writeFileProtected :: FilePath -> String -> IO ()+writeFileProtected :: RawFilePath -> String -> IO () writeFileProtected file content = writeFileProtected' file  	(\h -> hPutStr h content) -writeFileProtected' :: FilePath -> (Handle -> IO ()) -> IO ()+writeFileProtected' :: RawFilePath -> (Handle -> IO ()) -> IO () writeFileProtected' file writer = protectedOutput $-	withFile file WriteMode $ \h -> do+	withFile (fromRawFilePath file) WriteMode $ \h -> do 		void $ tryIO $ modifyFileMode file $ removeModes otherGroupModes 		writer h 
Utility/FileSize.hs view
@@ -1,5 +1,7 @@ {- File size.  -+ - Copyright 2015-2020 Joey Hess <id@joeyh.name>+ -  - License: BSD-2-clause  -} @@ -13,9 +15,11 @@ ) where  import System.PosixCompat.Files+import qualified Utility.RawFilePath as R #ifdef mingw32_HOST_OS import Control.Exception (bracket) import System.IO+import Utility.FileSystemEncoding #endif  type FileSize = Integer@@ -26,18 +30,18 @@  - FileOffset which maxes out at 2 gb.  - See https://github.com/jystic/unix-compat/issues/16  -}-getFileSize :: FilePath -> IO FileSize+getFileSize :: R.RawFilePath -> IO FileSize #ifndef mingw32_HOST_OS-getFileSize f = fmap (fromIntegral . fileSize) (getFileStatus f)+getFileSize f = fmap (fromIntegral . fileSize) (R.getFileStatus f) #else-getFileSize f = bracket (openFile f ReadMode) hClose hFileSize+getFileSize f = bracket (openFile (fromRawFilePath f) ReadMode) hClose hFileSize #endif  {- Gets the size of the file, when its FileStatus is already known.  -  - On windows, uses getFileSize. Otherwise, the FileStatus contains the  - size, so this does not do any work. -}-getFileSize' :: FilePath -> FileStatus -> IO FileSize+getFileSize' :: R.RawFilePath -> FileStatus -> IO FileSize #ifndef mingw32_HOST_OS getFileSize' _ s = return $ fromIntegral $ fileSize s #else
Utility/Gpg.hs view
@@ -422,7 +422,7 @@ 		orig <- getEnv var 		subdir <- makenewdir (1 :: Integer) 		-- gpg is picky about permissions on its home dir-		liftIO $ void $ tryIO $ modifyFileMode subdir $+		liftIO $ void $ tryIO $ modifyFileMode (toRawFilePath subdir) $ 			removeModes $ otherGroupModes 		setEnv var subdir True 		-- For some reason, recent gpg needs a trustdb to be set up.
Utility/InodeCache.hs view
@@ -186,15 +186,15 @@  genInodeCache :: RawFilePath -> TSDelta -> IO (Maybe InodeCache) genInodeCache f delta = catchDefaultIO Nothing $-	toInodeCache delta (fromRawFilePath f) =<< R.getFileStatus f+	toInodeCache delta f =<< R.getFileStatus f -toInodeCache :: TSDelta -> FilePath -> FileStatus -> IO (Maybe InodeCache)+toInodeCache :: TSDelta -> RawFilePath -> FileStatus -> IO (Maybe InodeCache) toInodeCache (TSDelta getdelta) f s 	| isRegularFile s = do 		delta <- getdelta 		sz <- getFileSize' f s #ifdef mingw32_HOST_OS-		mtime <- utcTimeToPOSIXSeconds <$> getModificationTime f+		mtime <- utcTimeToPOSIXSeconds <$> getModificationTime (fromRawFilePath f) #else 		let mtime = modificationTimeHiRes s #endif
Utility/LinuxMkLibs.hs view
@@ -18,7 +18,9 @@ import Utility.Process import Utility.Monad import Utility.Path+import Utility.Path.AbsRel import Utility.Split+import Utility.FileSystemEncoding  import Data.Maybe import System.FilePath@@ -35,18 +37,20 @@ 	( do 		installfile top lib 		checksymlink lib-		return $ Just $ parentDir lib+		return $ Just $ fromRawFilePath $ parentDir $ toRawFilePath lib 	, return Nothing 	)   where 	checksymlink f = whenM (isSymbolicLink <$> getSymbolicLinkStatus (inTop top f)) $ do 		l <- readSymbolicLink (inTop top f)-		let absl = absPathFrom (parentDir f) l-		target <- relPathDirToFile (takeDirectory f) absl-		installfile top absl-		nukeFile (top ++ f)-		createSymbolicLink target (inTop top f)-		checksymlink absl+		let absl = absPathFrom+			(parentDir (toRawFilePath f))+			(toRawFilePath l)+		target <- relPathDirToFile (toRawFilePath (takeDirectory f)) absl+		installfile top (fromRawFilePath absl)+		removeWhenExistsWith removeLink (top ++ f)+		createSymbolicLink (fromRawFilePath target) (inTop top f)+		checksymlink (fromRawFilePath absl)  -- Note that f is not relative, so cannot use </> inTop :: FilePath -> FilePath -> FilePath
Utility/LockFile/PidLock.hs view
@@ -5,6 +5,8 @@  - License: BSD-2-clause  -} +{-# LANGUAGE OverloadedStrings #-}+ module Utility.LockFile.PidLock ( 	LockHandle, 	tryLock,@@ -23,7 +25,7 @@ import Utility.Applicative import Utility.Directory import Utility.Monad-import Utility.Path+import Utility.Path.AbsRel import Utility.FileMode import Utility.LockFile.LockStatus import Utility.ThreadScheduler@@ -34,12 +36,13 @@ import qualified Utility.LockFile.Posix as Posix  import System.IO-import System.Posix.IO import System.Posix.Types-import System.Posix.Files+import System.Posix.IO.ByteString+import System.Posix.Files.ByteString import System.Posix.Process import Control.Monad import Control.Monad.IO.Class (liftIO, MonadIO)+import qualified System.FilePath.ByteString as P import Data.Maybe import Data.List import Network.BSD@@ -47,7 +50,7 @@ import Control.Applicative import Prelude -type LockFile = FilePath+type LockFile = RawFilePath  data LockHandle 	= LockHandle LockFile FileStatus SideLockHandle@@ -67,7 +70,8 @@ 	<*> getHostName  readPidLock :: LockFile -> IO (Maybe PidLock)-readPidLock lockfile = (readish =<<) <$> catchMaybeIO (readFile lockfile)+readPidLock lockfile = (readish =<<)+	<$> catchMaybeIO (readFile (fromRawFilePath lockfile))  -- To avoid races when taking over a stale pid lock, a side lock is used. -- This is a regular posix exclusive lock.@@ -100,7 +104,7 @@ 	-- to take the side lock will only succeed once the file is 	-- deleted, and so will be able to immediately see that it's taken 	-- a stale lock.-	_ <- tryIO $ removeFile f +	_ <- tryIO $ removeFile (fromRawFilePath f) 	Posix.dropLock h  -- The side lock is put in /dev/shm. This will work on most any@@ -108,17 +112,17 @@ -- locks. /tmp is used as a fallback. sideLockFile :: LockFile -> IO LockFile sideLockFile lockfile = do-	f <- absPath lockfile+	f <- fromRawFilePath <$> absPath lockfile 	let base = intercalate "_" (splitDirectories (makeRelative "/" f)) 	let shortbase = reverse $ take 32 $ reverse base 	let md5sum = if base == shortbase 		then ""-		else show (md5 (encodeBL base))+		else toRawFilePath $ show (md5 (encodeBL base)) 	dir <- ifM (doesDirectoryExist "/dev/shm") 		( return "/dev/shm" 		, return "/tmp" 		)-	return $ dir </> md5sum ++ shortbase ++ ".lck"+	return $ dir P.</> md5sum <> toRawFilePath shortbase <> ".lck"  -- | Tries to take a lock; does not block when the lock is already held. --@@ -138,18 +142,20 @@ 		_ -> return (Just ParentLocked)   where 	go abslockfile sidelock = do-		(tmp, h) <- openTempFile (takeDirectory abslockfile) "locktmp"-		setFileMode tmp (combineModes readModes)+		let abslockfile' = fromRawFilePath abslockfile+		(tmp, h) <- openTempFile (takeDirectory abslockfile') "locktmp"+		let tmp' = toRawFilePath tmp+		setFileMode tmp' (combineModes readModes) 		hPutStr h . show =<< mkPidLock 		hClose h 		let failedlock st = do-			dropLock $ LockHandle tmp st sidelock-			nukeFile tmp+			dropLock $ LockHandle tmp' st sidelock+			removeWhenExistsWith removeLink tmp' 			return Nothing 		let tooklock st = return $ Just $ LockHandle abslockfile st sidelock-		ifM (linkToLock sidelock tmp abslockfile)+		ifM (linkToLock sidelock tmp' abslockfile) 			( do-				nukeFile tmp+				removeWhenExistsWith removeLink tmp' 				-- May not have made a hard link, so stat 				-- the lockfile 				lckst <- getFileStatus abslockfile@@ -157,7 +163,7 @@ 			, do 				v <- readPidLock abslockfile 				hn <- getHostName-				tmpst <- getFileStatus tmp+				tmpst <- getFileStatus tmp' 				case v of 					Just pl | isJust sidelock && hn == lockingHost pl -> do 						-- Since we have the sidelock,@@ -165,7 +171,7 @@ 						-- the pidlock was taken on, 						-- we know that the pidlock is 						-- stale, and can take it over.-						rename tmp abslockfile+						rename tmp' abslockfile 						tooklock tmpst 					_ -> failedlock tmpst 			)@@ -180,12 +186,12 @@ -- -- However, not all filesystems support hard links. So, first probe -- to see if they are supported. If not, use open with O_EXCL.-linkToLock :: SideLockHandle -> FilePath -> FilePath -> IO Bool+linkToLock :: SideLockHandle -> RawFilePath -> RawFilePath -> IO Bool linkToLock Nothing _ _ = return False linkToLock (Just _) src dest = do-	let probe = src ++ ".lnk"+	let probe = src <> ".lnk" 	v <- tryIO $ createLink src probe-	nukeFile probe+	removeWhenExistsWith removeLink probe 	case v of 		Right _ -> do 			_ <- tryIO $ createLink src dest@@ -200,7 +206,8 @@ 					(defaultFileFlags {exclusive = True}) 				fdToHandle fd 			let cleanup = hClose-			bracket setup cleanup (\h -> readFile src >>= hPutStr h)+			let go h = readFile (fromRawFilePath src) >>= hPutStr h+			bracket setup cleanup go 			return True   where 	checklinked = do@@ -228,16 +235,17 @@ -- We can detect this insanity by getting the directory contents after -- making the link, and checking to see if 2 copies of the dest file, -- with the SAME FILENAME exist.-checkInsaneLustre :: FilePath -> IO Bool+checkInsaneLustre :: RawFilePath -> IO Bool checkInsaneLustre dest = do-	fs <- dirContents (takeDirectory dest)-	case length (filter (== dest) fs) of+	let dest' = fromRawFilePath dest+	fs <- dirContents (takeDirectory dest')+	case length (filter (== dest') fs) of 		1 -> return False -- whew! 		0 -> return True -- wtf? 		_ -> do 			-- Try to clean up the extra copy we made 			-- that has the same name. Egads.-			_ <- tryIO $ removeFile dest+			_ <- tryIO $ removeFile dest' 			return True  -- | Waits as necessary to take a lock.@@ -253,20 +261,20 @@ 		| n > 0 = liftIO (tryLock lockfile) >>= \case 			Nothing -> do 				when (n == pred timeout) $-					displaymessage $ "waiting for pid lock file " ++ lockfile ++ " which is held by another process (or may be stale)"+					displaymessage $ "waiting for pid lock file " ++ fromRawFilePath lockfile ++ " which is held by another process (or may be stale)" 				liftIO $ threadDelaySeconds (Seconds 1) 				go (pred n) 			Just lckh -> return lckh 		| otherwise = do-			displaymessage $ show timeout ++ " second timeout exceeded while waiting for pid lock file " ++ lockfile-			giveup $ "Gave up waiting for pid lock file " ++ lockfile+			displaymessage $ show timeout ++ " second timeout exceeded while waiting for pid lock file " ++ fromRawFilePath lockfile+			giveup $ "Gave up waiting for pid lock file " ++ fromRawFilePath lockfile  dropLock :: LockHandle -> IO () dropLock (LockHandle lockfile _ sidelock) = do 	-- Drop side lock first, at which point the pid lock will be 	-- considered stale. 	dropSideLock sidelock-	nukeFile lockfile+	removeWhenExistsWith removeLink lockfile dropLock ParentLocked = return ()  getLockStatus :: LockFile -> IO LockStatus@@ -297,9 +305,9 @@ -- The parent process should keep running as long as the child -- process is running, since the child inherits the environment and will -- not see unsetLockEnv.-pidLockEnv :: FilePath -> IO String+pidLockEnv :: RawFilePath -> IO String pidLockEnv lockfile = do-	abslockfile <- absPath lockfile+	abslockfile <- fromRawFilePath <$> absPath lockfile 	return $ "PIDLOCK_" ++ filter legalInEnvVar abslockfile  pidLockEnvValue :: String
Utility/LockFile/Posix.hs view
@@ -25,10 +25,13 @@ import Utility.LockFile.LockStatus  import System.IO-import System.Posix+import System.Posix.Types+import System.Posix.IO.ByteString+import System.Posix.Files.ByteString+import System.FilePath.ByteString (RawFilePath) import Data.Maybe -type LockFile = FilePath+type LockFile = RawFilePath  newtype LockHandle = LockHandle Fd 
Utility/LockFile/Windows.hs view
@@ -16,9 +16,12 @@ import System.Win32.Types import System.Win32.File import Control.Concurrent+import System.FilePath.ByteString (RawFilePath) -type LockFile = FilePath+import Utility.FileSystemEncoding +type LockFile = RawFilePath+ type LockHandle = HANDLE  {- Tries to lock a file with a shared lock, which allows other processes to@@ -51,7 +54,7 @@  -} openLock :: ShareMode -> LockFile -> IO (Maybe LockHandle) openLock sharemode f = do-	h <- withTString f $ \c_f ->+	h <- withTString (fromRawFilePath f) $ \c_f -> 		c_CreateFile c_f gENERIC_READ sharemode security_attributes 			oPEN_ALWAYS fILE_ATTRIBUTE_NORMAL (maybePtr Nothing) 	return $ if h == iNVALID_HANDLE_VALUE
Utility/LockPool/STM.hs view
@@ -22,6 +22,7 @@ import Utility.Monad  import System.IO.Unsafe (unsafePerformIO)+import System.FilePath.ByteString (RawFilePath) import qualified Data.Map.Strict as M import Control.Concurrent.STM import Control.Exception@@ -29,7 +30,7 @@ import Control.Applicative import Prelude -type LockFile = FilePath+type LockFile = RawFilePath  data LockMode = LockExclusive | LockShared 	deriving (Eq)
Utility/Metered.hs view
@@ -223,7 +223,8 @@ 			p sz 		watcher sz 	getsz = catchDefaultIO zeroBytesProcessed $-		toBytesProcessed <$> getFileSize f+		toBytesProcessed <$> getFileSize f'+	f' = toRawFilePath f  data OutputHandler = OutputHandler 	{ quietMode :: Bool
+ Utility/MoveFile.hs view
@@ -0,0 +1,74 @@+{- moving files+ -+ - Copyright 2011-2020 Joey Hess <id@joeyh.name>+ -+ - License: BSD-2-clause+ -}++{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}++module Utility.MoveFile (+	moveFile,+) where++import Control.Monad+import System.FilePath+import System.PosixCompat.Files+import Control.Monad.IfElse+import System.IO.Error+import Prelude++#ifndef mingw32_HOST_OS+import Utility.SafeCommand+#endif++import Utility.SystemDirectory+import Utility.Tmp+import Utility.Exception+import Utility.Monad++{- Moves one filename to another.+ - First tries a rename, but falls back to moving across devices if needed. -}+moveFile :: FilePath -> FilePath -> IO ()+moveFile src dest = tryIO (rename src dest) >>= onrename+  where+	onrename (Right _) = noop+	onrename (Left e)+		| isPermissionError e = rethrow+		| isDoesNotExistError e = rethrow+		| otherwise = viaTmp mv dest ()+	  where+		rethrow = throwM e++		mv tmp () = do+			-- copyFile is likely not as optimised as+			-- the mv command, so we'll use the command.+			--+			-- But, while Windows has a "mv", it does not seem very+			-- reliable, so use copyFile there.+#ifndef mingw32_HOST_OS	+			-- If dest is a directory, mv would move the file+			-- into it, which is not desired.+			whenM (isdir dest) rethrow+			ok <- boolSystem "mv" [Param "-f", Param src, Param tmp]+			let e' = e+#else+			r <- tryIO $ copyFile src tmp+			let (ok, e') = case r of+				Left err -> (False, err)+				Right _ -> (True, e)+#endif+			unless ok $ do+				-- delete any partial+				_ <- tryIO $ removeFile tmp+				throwM e'++#ifndef mingw32_HOST_OS	+	isdir f = do+		r <- tryIO $ getFileStatus f+		case r of+			(Left _) -> return False+			(Right s) -> return $ isDirectory s+#endif
Utility/Path.hs view
@@ -5,62 +5,55 @@  - License: BSD-2-clause  -} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-tabs #-}  module Utility.Path ( 	simplifyPath,-	absPathFrom, 	parentDir, 	upFrom, 	dirContains,-	absPath,-	relPathCwdToFile,-	relPathDirToFile,-	relPathDirToFileAbs, 	segmentPaths, 	segmentPaths', 	runSegmentPaths, 	runSegmentPaths',-	relHome, 	inPath, 	searchPath, 	dotfile, 	splitShortExtensions,--	prop_upFrom_basics,-	prop_relPathDirToFile_basics,-	prop_relPathDirToFile_regressionTest,+	relPathDirToFileAbs, ) where -import System.FilePath+import System.FilePath.ByteString+import qualified System.FilePath as P+import qualified Data.ByteString as B import Data.List import Data.Maybe-#ifdef mingw32_HOST_OS-import Data.Char-#endif import Control.Applicative import Prelude  import Utility.Monad-import Utility.UserInfo import Utility.SystemDirectory-import Utility.Split++#ifdef mingw32_HOST_OS+import Data.Char import Utility.FileSystemEncoding+#endif  {- Simplifies a path, removing any "." component, collapsing "dir/..",   - and removing the trailing path separator.  -  - On Windows, preserves whichever style of path separator might be used in- - the input FilePaths. This is done because some programs in Windows+ - the input RawFilePaths. This is done because some programs in Windows  - demand a particular path separator -- and which one actually varies!  -  - This does not guarantee that two paths that refer to the same location,  - and are both relative to the same location (or both absolute) will- - yeild the same result. Run both through normalise from System.FilePath+ - yeild the same result. Run both through normalise from System.RawFilePath  - to ensure that.  -}-simplifyPath :: FilePath -> FilePath+simplifyPath :: RawFilePath -> RawFilePath simplifyPath path = dropTrailingPathSeparator $  	joinDrive drive $ joinPath $ norm [] $ splitPath path'   where@@ -75,134 +68,37 @@ 	  where 		p' = dropTrailingPathSeparator p -{- Makes a path absolute.- -- - Also simplifies it using simplifyPath.- -- - The first parameter is a base directory (ie, the cwd) to use if the path- - is not already absolute, and should itsef be absolute.- -- - Does not attempt to deal with edge cases or ensure security with- - untrusted inputs.- -}-absPathFrom :: FilePath -> FilePath -> FilePath-absPathFrom dir path = simplifyPath (combine dir path)- {- takeDirectory "foo/bar/" is "foo/bar". This instead yields "foo" -}-parentDir :: FilePath -> FilePath+parentDir :: RawFilePath -> RawFilePath parentDir = takeDirectory . dropTrailingPathSeparator  {- Just the parent directory of a path, or Nothing if the path has no - parent (ie for "/" or "." or "foo") -}-upFrom :: FilePath -> Maybe FilePath+upFrom :: RawFilePath -> Maybe RawFilePath upFrom dir 	| length dirs < 2 = Nothing-	| otherwise = Just $ joinDrive drive $ intercalate s $ init dirs+	| otherwise = Just $ joinDrive drive $+		B.intercalate (B.singleton pathSeparator) $ init dirs   where 	-- on Unix, the drive will be "/" when the dir is absolute, 	-- otherwise "" 	(drive, path) = splitDrive dir-	s = [pathSeparator]-	dirs = filter (not . null) $ split s path--prop_upFrom_basics :: FilePath -> Bool-prop_upFrom_basics dir-	| null dir = True-	| dir == "/" = p == Nothing-	| otherwise = p /= Just dir-  where-	p = upFrom dir+	dirs = filter (not . B.null) $ B.splitWith isPathSeparator path -{- Checks if the first FilePath is, or could be said to contain the second.+{- Checks if the first RawFilePath is, or could be said to contain the second.  - For example, "foo/" contains "foo/bar". Also, "foo", "./foo", "foo/" etc  - are all equivilant.  -}-dirContains :: FilePath -> FilePath -> Bool+dirContains :: RawFilePath -> RawFilePath -> Bool dirContains a b = a == b 	|| a' == b'-	|| (addTrailingPathSeparator a') `isPrefixOf` b'+	|| (addTrailingPathSeparator a') `B.isPrefixOf` b' 	|| a' == "." && normalise ("." </> b') == b'   where 	a' = norm a 	b' = norm b 	norm = normalise . simplifyPath -{- Converts a filename into an absolute path.- -- - Also simplifies it using simplifyPath.- -- - Unlike Directory.canonicalizePath, this does not require the path- - already exists. -}-absPath :: FilePath -> IO FilePath-absPath file-	-- Avoid unncessarily getting the current directory when the path-	-- is already absolute. absPathFrom uses simplifyPath-	-- so also used here for consistency.-	| isAbsolute file = return $ simplifyPath file-	| otherwise = do-		cwd <- getCurrentDirectory-		return $ absPathFrom cwd file--{- Constructs a relative path from the CWD to a file.- -- - For example, assuming CWD is /tmp/foo/bar:- -    relPathCwdToFile "/tmp/foo" == ".."- -    relPathCwdToFile "/tmp/foo/bar" == "" - -}-relPathCwdToFile :: FilePath -> IO FilePath-relPathCwdToFile f = do-	c <- getCurrentDirectory-	relPathDirToFile c f--{- Constructs a relative path from a directory to a file. -}-relPathDirToFile :: FilePath -> FilePath -> IO FilePath-relPathDirToFile from to = relPathDirToFileAbs <$> absPath from <*> absPath to--{- This requires the first path to be absolute, and the- - second path cannot contain ../ or ./- -- - On Windows, if the paths are on different drives,- - a relative path is not possible and the path is simply- - returned as-is.- -}-relPathDirToFileAbs :: FilePath -> FilePath -> FilePath-relPathDirToFileAbs from to-#ifdef mingw32_HOST_OS-	| normdrive from /= normdrive to = to-#endif-	| otherwise = joinPath $ dotdots ++ uncommon-  where-	pfrom = sp from-	pto = sp to-	sp = map dropTrailingPathSeparator . splitPath . dropDrive-	common = map fst $ takeWhile same $ zip pfrom pto-	same (c,d) = c == d-	uncommon = drop numcommon pto-	dotdots = replicate (length pfrom - numcommon) ".."-	numcommon = length common-#ifdef mingw32_HOST_OS-	normdrive = map toLower . takeWhile (/= ':') . takeDrive-#endif--prop_relPathDirToFile_basics :: FilePath -> FilePath -> Bool-prop_relPathDirToFile_basics from to-	| null from || null to = True-	| from == to = null r-	| otherwise = not (null r)-  where-	r = relPathDirToFileAbs from to --prop_relPathDirToFile_regressionTest :: Bool-prop_relPathDirToFile_regressionTest = same_dir_shortcurcuits_at_difference-  where-	{- Two paths have the same directory component at the same-	 - location, but it's not really the same directory.-	 - Code used to get this wrong. -}-	same_dir_shortcurcuits_at_difference =-		relPathDirToFileAbs (joinPath [pathSeparator : "tmp", "r", "lll", "xxx", "yyy", "18"])-			(joinPath [pathSeparator : "tmp", "r", ".git", "annex", "objects", "18", "gk", "SHA256-foo", "SHA256-foo"])-				== joinPath ["..", "..", "..", "..", ".git", "annex", "objects", "18", "gk", "SHA256-foo", "SHA256-foo"]- {- Given an original list of paths, and an expanded list derived from it,  - which may be arbitrarily reordered, generates a list of lists, where  - each sublist corresponds to one of the original paths.@@ -228,8 +124,7 @@ 	(found, rest) = if length is < 100 		then partition ini new 		else break (not . ini) new-	ini p = i' `dirContains` fromRawFilePath (c p)-	i' = fromRawFilePath i+	ini p = i `dirContains` c p  {- This assumes that it's cheaper to call segmentPaths on the result,  - than it would be to run the action separately with each path. In@@ -241,14 +136,6 @@ runSegmentPaths' :: (Maybe RawFilePath -> a -> r) -> (a -> RawFilePath) -> ([RawFilePath] -> IO [a]) -> [RawFilePath] -> IO [[r]] runSegmentPaths' si c a paths = segmentPaths' si c paths <$> a paths -{- Converts paths in the home directory to use ~/ -}-relHome :: FilePath -> IO String-relHome path = do-	home <- myHomeDir-	return $ if dirContains home path-		then "~/" ++ relPathDirToFileAbs home path-		else path- {- Checks if a command is available in PATH.  -  - The command may be fully-qualified, in which case, this succeeds as@@ -265,10 +152,10 @@  -} searchPath :: String -> IO (Maybe FilePath) searchPath command-	| isAbsolute command = check command-	| otherwise = getSearchPath >>= getM indir+	| P.isAbsolute command = check command+	| otherwise = P.getSearchPath >>= getM indir   where-	indir d = check $ d </> command+	indir d = check $ d P.</> command 	check f = firstM doesFileExist #ifdef mingw32_HOST_OS 		[f, f ++ ".exe"]@@ -278,26 +165,52 @@  {- Checks if a filename is a unix dotfile. All files inside dotdirs  - count as dotfiles. -}-dotfile :: FilePath -> Bool+dotfile :: RawFilePath -> Bool dotfile file 	| f == "." = False 	| f == ".." = False 	| f == "" = False-	| otherwise = "." `isPrefixOf` f || dotfile (takeDirectory file)+	| otherwise = "." `B.isPrefixOf` f || dotfile (takeDirectory file)   where 	f = takeFileName file -{- Similar to splitExtensions, but knows that some things in FilePaths+{- Similar to splitExtensions, but knows that some things in RawFilePaths  - after a dot are too long to be extensions. -}-splitShortExtensions :: FilePath -> (FilePath, [String])+splitShortExtensions :: RawFilePath -> (RawFilePath, [B.ByteString]) splitShortExtensions = splitShortExtensions' 5 -- enough for ".jpeg"-splitShortExtensions' :: Int -> FilePath -> (FilePath, [String])+splitShortExtensions' :: Int -> RawFilePath -> (RawFilePath, [B.ByteString]) splitShortExtensions' maxextension = go []   where 	go c f-		| len > 0 && len <= maxextension && not (null base) = +		| len > 0 && len <= maxextension && not (B.null base) =  			go (ext:c) base 		| otherwise = (f, c) 	  where 		(base, ext) = splitExtension f-		len = length ext+		len = B.length ext++{- This requires the first path to be absolute, and the+ - second path cannot contain ../ or ./+ -+ - On Windows, if the paths are on different drives,+ - a relative path is not possible and the path is simply+ - returned as-is.+ -}+relPathDirToFileAbs :: RawFilePath -> RawFilePath -> RawFilePath+relPathDirToFileAbs from to+#ifdef mingw32_HOST_OS+	| normdrive from /= normdrive to = to+#endif+	| otherwise = joinPath $ dotdots ++ uncommon+  where+	pfrom = sp from+	pto = sp to+	sp = map dropTrailingPathSeparator . splitPath . dropDrive+	common = map fst $ takeWhile same $ zip pfrom pto+	same (c,d) = c == d+	uncommon = drop numcommon pto+	dotdots = replicate (length pfrom - numcommon) ".."+	numcommon = length common+#ifdef mingw32_HOST_OS+	normdrive = map toLower . takeWhile (/= ':') . fromRawFilePath . takeDrive+#endif
+ Utility/Path/AbsRel.hs view
@@ -0,0 +1,93 @@+{- absolute and relative path manipulation+ -+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>+ -+ - License: BSD-2-clause+ -}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}++module Utility.Path.AbsRel (+	absPathFrom,+	absPath,+	relPathCwdToFile,+	relPathDirToFile,+	relPathDirToFileAbs,+	relHome,+) where++import System.FilePath.ByteString+#ifdef mingw32_HOST_OS+import System.Directory (getCurrentDirectory)+#else+import System.Posix.Directory.ByteString (getWorkingDirectory)+#endif+import Control.Applicative+import Prelude++import Utility.Path+import Utility.UserInfo+import Utility.FileSystemEncoding++{- Makes a path absolute.+ -+ - Also simplifies it using simplifyPath.+ -+ - The first parameter is a base directory (ie, the cwd) to use if the path+ - is not already absolute, and should itsef be absolute.+ -+ - Does not attempt to deal with edge cases or ensure security with+ - untrusted inputs.+ -}+absPathFrom :: RawFilePath -> RawFilePath -> RawFilePath+absPathFrom dir path = simplifyPath (combine dir path)++{- Converts a filename into an absolute path.+ -+ - Also simplifies it using simplifyPath.+ -+ - Unlike Directory.canonicalizePath, this does not require the path+ - already exists. -}+absPath :: RawFilePath -> IO RawFilePath+absPath file+	-- Avoid unncessarily getting the current directory when the path+	-- is already absolute. absPathFrom uses simplifyPath+	-- so also used here for consistency.+	| isAbsolute file = return $ simplifyPath file+	| otherwise = do+#ifdef mingw32_HOST_OS+		cwd <- toRawFilePath <$> getCurrentDirectory+#else+		cwd <- getWorkingDirectory+#endif+		return $ absPathFrom cwd file++{- Constructs a relative path from the CWD to a file.+ -+ - For example, assuming CWD is /tmp/foo/bar:+ -    relPathCwdToFile "/tmp/foo" == ".."+ -    relPathCwdToFile "/tmp/foo/bar" == "" + -}+relPathCwdToFile :: RawFilePath -> IO RawFilePath+relPathCwdToFile f = do+#ifdef mingw32_HOST_OS+	c <- toRawFilePath <$> getCurrentDirectory+#else+	c <- getWorkingDirectory+#endif+	relPathDirToFile c f++{- Constructs a relative path from a directory to a file. -}+relPathDirToFile :: RawFilePath -> RawFilePath -> IO RawFilePath+relPathDirToFile from to = relPathDirToFileAbs <$> absPath from <*> absPath to++{- Converts paths in the home directory to use ~/ -}+relHome :: FilePath -> IO String+relHome path = do+	let path' = toRawFilePath path+	home <- toRawFilePath <$> myHomeDir+	return $ if dirContains home path'+		then fromRawFilePath ("~/" <> relPathDirToFileAbs home path')+		else path
+ Utility/Path/Tests.hs view
@@ -0,0 +1,58 @@+{- Tests for Utility.Path. Split into a separate module to avoid it needing+ - QuickCheck.+ -+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>+ -+ - License: BSD-2-clause+ -}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}++module Utility.Path.Tests (+	prop_upFrom_basics,+	prop_relPathDirToFileAbs_basics,+	prop_relPathDirToFileAbs_regressionTest,+) where++import System.FilePath.ByteString+import qualified Data.ByteString as B+import Data.List+import Data.Maybe+import Control.Applicative+import Prelude++import Utility.Path+import Utility.FileSystemEncoding+import Utility.QuickCheck++prop_upFrom_basics :: TestableFilePath -> Bool+prop_upFrom_basics tdir+	| dir == "/" = p == Nothing+	| otherwise = p /= Just dir+  where+	p = fromRawFilePath <$> upFrom (toRawFilePath dir)+	dir = fromTestableFilePath tdir++prop_relPathDirToFileAbs_basics :: TestableFilePath -> TestableFilePath -> Bool+prop_relPathDirToFileAbs_basics fromt tot+	| from == to = null r+	| otherwise = not (null r)+  where+	from = fromTestableFilePath fromt+	to = fromTestableFilePath tot+	r = fromRawFilePath $ relPathDirToFileAbs+		(toRawFilePath from)+		(toRawFilePath to)++prop_relPathDirToFileAbs_regressionTest :: Bool+prop_relPathDirToFileAbs_regressionTest = same_dir_shortcurcuits_at_difference+  where+	{- Two paths have the same directory component at the same+	 - location, but it's not really the same directory.+	 - Code used to get this wrong. -}+	same_dir_shortcurcuits_at_difference =+		relPathDirToFileAbs (joinPath [pathSeparator `B.cons` "tmp", "r", "lll", "xxx", "yyy", "18"])+			(joinPath [pathSeparator `B.cons` "tmp", "r", ".git", "annex", "objects", "18", "gk", "SHA256-foo", "SHA256-foo"])+				== joinPath ["..", "..", "..", "..", ".git", "annex", "objects", "18", "gk", "SHA256-foo", "SHA256-foo"]
Utility/QuickCheck.hs view
@@ -1,6 +1,6 @@ {- QuickCheck with additional instances  -- - Copyright 2012-2014 Joey Hess <id@joeyh.name>+ - Copyright 2012-2020 Joey Hess <id@joeyh.name>  -  - License: BSD-2-clause  -}@@ -10,15 +10,52 @@  module Utility.QuickCheck 	( module X-	, module Utility.QuickCheck+	, TestableString+	, fromTestableString+	, TestableFilePath+	, fromTestableFilePath+	, nonNegative+	, positive 	) where  import Test.QuickCheck as X import Data.Time.Clock.POSIX import Data.Ratio+import Data.Char import System.Posix.Types import Data.List.NonEmpty (NonEmpty(..)) import Prelude++{- A String, but Arbitrary is limited to ascii.+ -+ - When in a non-utf8 locale, String does not normally contain any non-ascii+ - characters, except for ones in surrogate plane. Converting a string that+ - does contain other unicode characters to a ByteString using the+ - filesystem encoding (see GHC.IO.Encoding) will throw an exception,+ - so use this instead to avoid quickcheck tests breaking unncessarily.+ -} +newtype TestableString = TestableString+	{ fromTestableString :: String }+	deriving (Show)++instance Arbitrary TestableString where+	arbitrary = TestableString . filter isAscii <$> arbitrary++{- FilePath constrained to not be the empty string, not contain a NUL, + - and contain only ascii.+ -+ - No real-world filename can be empty or contain a NUL. So code can+ - well be written that assumes that and using this avoids quickcheck+ - tests breaking unncessarily.+ -} +newtype TestableFilePath = TestableFilePath+	{ fromTestableFilePath :: FilePath }+	deriving (Show)++instance Arbitrary TestableFilePath where+	arbitrary = (TestableFilePath . fromTestableString <$> arbitrary)+		`suchThat` (not . null . fromTestableFilePath)+		`suchThat` (not . any (== '\NUL') . fromTestableFilePath)  {- Times before the epoch are excluded. Half with decimal and half without. -} instance Arbitrary POSIXTime where
Utility/RawFilePath.hs view
@@ -1,4 +1,4 @@-{- Portability shim around System.Posix.Files.ByteString+{- Portability shim for basic operations on RawFilePaths.  -  - On unix, this makes syscalls using RawFilesPaths as efficiently as  - possible.@@ -7,40 +7,68 @@  - decoded. So this library will work, but less efficiently than using  - FilePath would.  -- - Copyright 2019 Joey Hess <id@joeyh.name>+ - Copyright 2019-2020 Joey Hess <id@joeyh.name>  -  - License: BSD-2-clause  -}  {-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}  module Utility.RawFilePath ( 	RawFilePath, 	readSymbolicLink,+	createSymbolicLink,+	createLink,+	removeLink, 	getFileStatus, 	getSymbolicLinkStatus, 	doesPathExist,+	getCurrentDirectory,+	createDirectory,+	setFileMode, ) where  #ifndef mingw32_HOST_OS import Utility.FileSystemEncoding (RawFilePath) import System.Posix.Files.ByteString+import qualified System.Posix.Directory.ByteString as D --- | Checks if a file or directoy exists. Note that a dangling symlink+-- | Checks if a file or directory exists. Note that a dangling symlink -- will be false. doesPathExist :: RawFilePath -> IO Bool doesPathExist = fileExist +getCurrentDirectory :: IO RawFilePath+getCurrentDirectory = D.getWorkingDirectory++createDirectory :: RawFilePath -> IO ()+createDirectory p = D.createDirectory p 0o777+ #else import qualified Data.ByteString as B-import System.PosixCompat (FileStatus)+import System.PosixCompat (FileStatus, FileMode) import qualified System.PosixCompat as P+import qualified System.PosixCompat.Files as F import qualified System.Directory as D import Utility.FileSystemEncoding  readSymbolicLink :: RawFilePath -> IO RawFilePath readSymbolicLink f = toRawFilePath <$> P.readSymbolicLink (fromRawFilePath f) +createSymbolicLink :: RawFilePath -> RawFilePath -> IO ()+createSymbolicLink a b = P.createSymbolicLink+	(fromRawFilePath a)+	(fromRawFilePath b)++createLink :: RawFilePath -> RawFilePath -> IO ()+createLink a b = P.createLink+	(fromRawFilePath a)+	(fromRawFilePath b)++removeLink :: RawFilePath -> IO ()+removeLink = P.removeLink . fromRawFilePath+ getFileStatus :: RawFilePath -> IO FileStatus getFileStatus = P.getFileStatus . fromRawFilePath @@ -49,4 +77,13 @@  doesPathExist :: RawFilePath -> IO Bool doesPathExist = D.doesPathExist . fromRawFilePath++getCurrentDirectory :: IO RawFilePath+getCurrentDirectory = toRawFilePath <$> D.getCurrentDirectory++createDirectory :: RawFilePath -> IO ()+createDirectory = D.createDirectory . fromRawFilePath++setFileMode :: RawFilePath -> FileMode -> IO () +setFileMode = F.setFileMode . fromRawFilePath #endif
Utility/SafeCommand.hs view
@@ -16,18 +16,13 @@ 	safeSystem, 	safeSystem', 	safeSystemEnv,-	shellWrap,-	shellEscape,-	shellUnEscape, 	segmentXargsOrdered, 	segmentXargsUnordered,-	prop_isomorphic_shellEscape,-	prop_isomorphic_shellEscape_multiword, ) where -import System.Exit import Utility.Process-import Utility.Split++import System.Exit import System.FilePath import Data.Char import Data.List@@ -92,44 +87,6 @@ safeSystemEnv :: FilePath -> [CommandParam] -> Maybe [(String, String)] -> IO ExitCode safeSystemEnv command params environ = safeSystem' command params $  	\p -> p { env = environ }---- | Wraps a shell command line inside sh -c, allowing it to be run in a--- login shell that may not support POSIX shell, eg csh.-shellWrap :: String -> String-shellWrap cmdline = "sh -c " ++ shellEscape cmdline---- | Escapes a filename or other parameter to be safely able to be exposed to--- the shell.------ This method works for POSIX shells, as well as other shells like csh.-shellEscape :: String -> String-shellEscape f = "'" ++ escaped ++ "'"-  where-	-- replace ' with '"'"'-	escaped = intercalate "'\"'\"'" $ splitc '\'' f---- | Unescapes a set of shellEscaped words or filenames.-shellUnEscape :: String -> [String]-shellUnEscape [] = []-shellUnEscape s = word : shellUnEscape rest-  where-	(word, rest) = findword "" s-	findword w [] = (w, "")-	findword w (c:cs)-		| c == ' ' = (w, cs)-		| c == '\'' = inquote c w cs-		| c == '"' = inquote c w cs-		| otherwise = findword (w++[c]) cs-	inquote _ w [] = (w, "")-	inquote q w (c:cs)-		| c == q = findword w cs-		| otherwise = inquote q (w++[c]) cs---- | For quickcheck.-prop_isomorphic_shellEscape :: String -> Bool-prop_isomorphic_shellEscape s = [s] == (shellUnEscape . shellEscape) s-prop_isomorphic_shellEscape_multiword :: [String] -> Bool-prop_isomorphic_shellEscape_multiword s = s == (shellUnEscape . unwords . map shellEscape) s  -- | Segments a list of filenames into groups that are all below the maximum --  command-line length limit.
+ Utility/ShellEscape.hs view
@@ -0,0 +1,65 @@+{- shell escaping+ -+ - Copyright 2010-2015 Joey Hess <id@joeyh.name>+ -+ - License: BSD-2-clause+ -}++{-# OPTIONS_GHC -fno-warn-tabs #-}++module Utility.ShellEscape (+	shellWrap,+	shellEscape,+	shellUnEscape,+	prop_isomorphic_shellEscape,+	prop_isomorphic_shellEscape_multiword,+) where++import Utility.QuickCheck+import Utility.Split++import Data.List+import Prelude++-- | Wraps a shell command line inside sh -c, allowing it to be run in a+-- login shell that may not support POSIX shell, eg csh.+shellWrap :: String -> String+shellWrap cmdline = "sh -c " ++ shellEscape cmdline++-- | Escapes a filename or other parameter to be safely able to be exposed to+-- the shell.+--+-- This method works for POSIX shells, as well as other shells like csh.+shellEscape :: String -> String+shellEscape f = "'" ++ escaped ++ "'"+  where+	-- replace ' with '"'"'+	escaped = intercalate "'\"'\"'" $ splitc '\'' f++-- | Unescapes a set of shellEscaped words or filenames.+shellUnEscape :: String -> [String]+shellUnEscape [] = []+shellUnEscape s = word : shellUnEscape rest+  where+	(word, rest) = findword "" s+	findword w [] = (w, "")+	findword w (c:cs)+		| c == ' ' = (w, cs)+		| c == '\'' = inquote c w cs+		| c == '"' = inquote c w cs+		| otherwise = findword (w++[c]) cs+	inquote _ w [] = (w, "")+	inquote q w (c:cs)+		| c == q = findword w cs+		| otherwise = inquote q (w++[c]) cs++prop_isomorphic_shellEscape :: TestableString -> Bool+prop_isomorphic_shellEscape ts = [s] == (shellUnEscape . shellEscape) s+  where+	s = fromTestableString ts++prop_isomorphic_shellEscape_multiword :: [TestableString] -> Bool+prop_isomorphic_shellEscape_multiword ts =+	l == (shellUnEscape . unwords . map shellEscape) l+  where+	l = map fromTestableString ts
Utility/SshConfig.hs view
@@ -144,7 +144,7 @@ writeSshConfig :: FilePath -> String -> IO () writeSshConfig f s = do 	writeFile f s-	setSshConfigMode f+	setSshConfigMode (toRawFilePath f)  {- Ensure that the ssh config file lacks any group or other write bits,   - since ssh is paranoid about not working if other users can write@@ -153,7 +153,7 @@  - If the chmod fails, ignore the failure, as it might be a filesystem like  - Android's that does not support file modes.  -}-setSshConfigMode :: FilePath -> IO ()+setSshConfigMode :: RawFilePath -> IO () setSshConfigMode f = void $ tryIO $ modifyFileMode f $ 	removeModes [groupWriteMode, otherWriteMode] 
Utility/Tor.hs view
@@ -166,7 +166,7 @@ prepHiddenServiceSocketDir appname uid ident = do 	createDirectoryIfMissing True d 	setOwnerAndGroup d uid (-1)-	modifyFileMode d $+	modifyFileMode (toRawFilePath d) $ 		addModes [ownerReadMode, ownerExecuteMode, ownerWriteMode]   where 	d = takeDirectory $ hiddenServiceSocketFile appname uid ident
Utility/Touch.hs view
@@ -14,30 +14,32 @@  #if ! defined(mingw32_HOST_OS) -import System.Posix.Files+import System.FilePath.ByteString (RawFilePath)+import System.Posix.Files.ByteString import Data.Time.Clock.POSIX  {- Changes the access and modification times of an existing file.    Can follow symlinks, or not. -}-touchBoth :: FilePath -> POSIXTime -> POSIXTime -> Bool -> IO ()+touchBoth :: RawFilePath -> POSIXTime -> POSIXTime -> Bool -> IO () touchBoth file atime mtime follow 	| follow = setFileTimesHiRes file atime mtime 	| otherwise = setSymbolicLinkTimesHiRes file atime mtime  {- Changes the access and modification times of an existing file  - to the same value. Can follow symlinks, or not. -}-touch :: FilePath -> POSIXTime -> Bool -> IO ()+touch :: RawFilePath -> POSIXTime -> Bool -> IO () touch file mtime = touchBoth file mtime mtime  #else  import Data.Time.Clock.POSIX+import Utility.RawFilePath  {- Noop for Windows -}-touchBoth :: FilePath -> POSIXTime -> POSIXTime -> Bool -> IO ()+touchBoth :: RawFilePath -> POSIXTime -> POSIXTime -> Bool -> IO () touchBoth _ _ _ _ = return () -touch :: FilePath -> POSIXTime -> Bool -> IO ()+touch :: RawFilePath -> POSIXTime -> Bool -> IO () touch _ _ _ = return ()  #endif
Utility/Url.hs view
@@ -52,6 +52,7 @@ import Utility.HttpManagerRestricted #endif import Utility.IPAddress+import qualified Utility.RawFilePath as R  import Network.URI import Network.HTTP.Types@@ -309,8 +310,8 @@ 		=<< curlRestrictedParams r u defport (basecurlparams url')  	existsfile u = do-		let f = unEscapeString (uriPath u)-		s <- catchMaybeIO $ getFileStatus f+		let f = toRawFilePath (unEscapeString (uriPath u))+		s <- catchMaybeIO $ R.getFileStatus f 		case s of 			Just stat -> do 				sz <- getFileSize' f stat@@ -455,7 +456,7 @@  -} downloadConduit :: MeterUpdate -> Request -> FilePath -> UrlOptions -> IO () downloadConduit meterupdate req file uo =-	catchMaybeIO (getFileSize file) >>= \case+	catchMaybeIO (getFileSize (toRawFilePath file)) >>= \case 		Just sz | sz > 0 -> resumedownload sz 		_ -> join $ runResourceT $ do 			liftIO $ debugM "url" (show req')
Utility/Verifiable.hs view
@@ -18,6 +18,7 @@ import qualified Data.ByteString as S  import Utility.Hash+import Utility.QuickCheck  type Secret = S.ByteString type HMACDigest = String@@ -38,8 +39,8 @@ calcDigest :: String -> Secret -> HMACDigest calcDigest v secret = calcMac HmacSha1 secret (fromString v) -{- for quickcheck -}-prop_verifiable_sane :: String -> String -> Bool-prop_verifiable_sane a s = verify (mkVerifiable a secret) secret+prop_verifiable_sane :: TestableString -> TestableString -> Bool+prop_verifiable_sane v ts = +	verify (mkVerifiable (fromTestableString v) secret) secret   where-	secret = fromString s+	secret = fromString (fromTestableString ts)
Utility/WebApp.hs view
@@ -189,7 +189,8 @@ {- Creates a html shim file that's used to redirect into the webapp,  - to avoid exposing the secret token when launching the web browser. -} writeHtmlShim :: String -> String -> FilePath -> IO ()-writeHtmlShim title url file = viaTmp writeFileProtected file $ genHtmlShim title url+writeHtmlShim title url file = +	viaTmp (writeFileProtected . toRawFilePath) file $ genHtmlShim title url  genHtmlShim :: String -> String -> String genHtmlShim title url = unlines
doc/git-annex-examinekey.mdwn view
@@ -22,10 +22,14 @@   use '${var;width}' ; to left-justify a variable, use '${var;-width}';   to escape unusual characters in a variable, use '${escaped_var}' -  These variables are available for use in formats: key, backend,-  bytesize, humansize, keyname, hashdirlower, hashdirmixed, mtime (for-  the mtime field of a WORM key).+  To generate a path from the top of the repository to the git-annex+  object for a key, use ${objectpath}. To generate the value of a+  git-annex pointer file for a key, use ${objectpointer}. +  These variables are also available for use in formats: ${key}, ${backend},+  ${bytesize}, ${humansize}, ${keyname}, ${hashdirlower}, ${hashdirmixed},+  ${mtime} (for the mtime field of a WORM key).+   Also, '\\n' is a newline, '\\000' is a NULL, etc.  * `--json`@@ -38,16 +42,36 @@   Messages that would normally be output to standard error are included in   the json instead. +* `--migrate-to-backend=backend`++  Attempt to migrate the input key to the new backend specified. If+  successful, outputs information about the migrated key. Otherwise,+  outputs information about the input key.++  This only does fast migrations; it will not re-hash the content of a key+  or similar expensive operation.++  One way to use it is to add an extension to a key.++	git-annex examinekey SHA256--xxx --migrate-to-backend=SHA256E --filename=foo.tar.gz++  Or to remove the extension from a key:++  	git-annex examinekey SHA256E-xxx.tar.gz --migrate-to-backend=SHA256++* `--filename=name`++  The name of a file associated with the key, eg a work tree file.+  It does not need to exist. This is needed when using `--migrate-to-backend`+  to add an extension to the key.+ * `--batch`    Enable batch mode, in which a line containing a key is read from stdin,   the information about it is output to stdout, and repeat. -# EXAMPLES--The location where the content of a key is stored can be looked up by running:--	git annex examinekey $KEY --format='.git/annex/objects/${hashdirmixed}${key}/${key}'+  In order to also provide the name of a file associated with the key, the+  line can be in the format "$key $file"  # SEE ALSO 
git-annex.cabal view
@@ -1,5 +1,5 @@ Name: git-annex-Version: 8.20201103+Version: 8.20201116 Cabal-Version: >= 1.10 License: AGPL-3 Maintainer: Joey Hess <id@joeyh.name>@@ -298,7 +298,7 @@ custom-setup   Setup-Depends: base (>= 4.11.1.0), hslogger, split, unix-compat,      filepath, exceptions, bytestring, directory, IfElse, data-default,-    filepath-bytestring (>= 1.4.2.1.1),+    filepath-bytestring (>= 1.4.2.1.4),     process (>= 1.6.3),     async, utf8-string, transformers, Cabal @@ -817,6 +817,7 @@     Config     Config.Cost     Config.Files+    Config.Files.AutoStart     Config.DynamicConfig     Config.GitConfig     Config.Smudge@@ -1055,6 +1056,7 @@     Utility.DirWatcher     Utility.DirWatcher.Types     Utility.Directory+    Utility.Directory.Create     Utility.Directory.Stream     Utility.DiskFree     Utility.Dot@@ -1088,13 +1090,16 @@     Utility.Metered     Utility.Misc     Utility.Monad+    Utility.MoveFile     Utility.Network     Utility.NotificationBroadcaster     Utility.OptParse     Utility.PID     Utility.PartialPrelude     Utility.Path+    Utility.Path.AbsRel     Utility.Path.Max+    Utility.Path.Tests     Utility.Percentage     Utility.Process     Utility.Process.Shim@@ -1107,6 +1112,7 @@     Utility.Scheduled     Utility.Scheduled.QuickCheck     Utility.Shell+    Utility.ShellEscape     Utility.SimpleProtocol     Utility.Split     Utility.SshConfig