more RawFilePath conversion
authorJoey Hess <joeyh@joeyh.name>
Thu, 5 Nov 2020 22:45:37 +0000 (18:45 -0400)
committerJoey Hess <joeyh@joeyh.name>
Thu, 5 Nov 2020 22:45:37 +0000 (18:45 -0400)
Converted file mode setting to it, and follow-on changes.

Compiles up through 369/646.

This commit was sponsored by Ethan Aubin.

31 files changed:
Annex/Branch.hs
Annex/Content/LowLevel.hs
Annex/Content/PointerFile.hs
Annex/Link.hs
Annex/Locations.hs
Annex/Perms.hs
Assistant/Ssh.hs
Common.hs
Creds.hs
Database/Benchmark.hs
Database/ContentIdentifier.hs
Database/Export.hs
Database/Fsck.hs
Database/Handle.hs
Database/Init.hs
Database/Keys.hs
Database/Queue.hs
Git/Index.hs
Git/Objects.hs
Git/Repair.hs
Logs/File.hs
P2P/IO.hs
Utility/Directory.hs
Utility/FileMode.hs
Utility/Gpg.hs
Utility/MoveFile.hs [new file with mode: 0644]
Utility/RawFilePath.hs
Utility/SshConfig.hs
Utility/Tor.hs
Utility/WebApp.hs
git-annex.cabal

index df949e968cae27395b49bb6fbc98883bff2e494b..415980447b17b22ebdc2b089b3448a926bc60675 100644 (file)
@@ -77,6 +77,7 @@ import Annex.Branch.Transitions
 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
@@ -447,7 +448,7 @@ mergeIndex jl branches = do
 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
index b8e2bd847a5eaf9b66b36065b0319abbdd1242a1..f202e6e8cf1eb234b2772ffefde448993456c83a 100644 (file)
@@ -9,8 +9,6 @@
 
 module Annex.Content.LowLevel where
 
-import System.PosixCompat.Files
-
 import Annex.Common
 import Logs.Transfer
 import qualified Annex
@@ -20,6 +18,9 @@ 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. -}
@@ -59,32 +60,30 @@ linkOrCopy' canhardlink key src dest destmode = catchDefaultIO Nothing $
                s <- getstat
                if linkCount s > 1
                        then copy s
-                       else liftIO (R.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)
+       copy s = ifM (checkedCopyFile' key src dest destmode s)
                ( return (Just Copied)
                , return Nothing
                )
        getstat = liftIO $ R.getFileStatus src
-       src' = fromRawFilePath src
-       dest' = fromRawFilePath dest
 
 {- 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
@@ -102,12 +101,12 @@ preserveGitMode _ _ = return True
  - 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
@@ -120,7 +119,7 @@ checkDiskSpace' need destdir key alreadythere samefilesystem = ifM (Annex.getSta
                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
@@ -131,7 +130,7 @@ checkDiskSpace' need destdir key alreadythere samefilesystem = ifM (Annex.getSta
                        _ -> 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 " ++ 
index e13f2ad1ae5ba16cb8a4d33f0f5ed5b8e612ea17..1e23167a4244d62f101e7c0e9f28d6a7874adf5e 100644 (file)
@@ -43,7 +43,7 @@ populatePointerFile restage k obj f = go =<< liftIO (isPointerFile f)
                (ic, populated) <- replaceWorkTreeFile f' $ \tmp -> do
                        let tmp' = toRawFilePath tmp
                        ok <- linkOrCopy k obj tmp' destmode >>= \case
-                               Just _ -> thawContent tmp >> return True
+                               Just _ -> thawContent tmp' >> return True
                                Nothing -> liftIO (writePointerFile tmp' k destmode) >> return False
                        ic <- withTSDelta (liftIO . genInodeCache tmp')
                        return (ic, ok)
index b9f6a662df02c73b39254bbc78030d286b315945..d7353d78894a953abf03fff2ab228a4276e24492 100644 (file)
@@ -203,7 +203,7 @@ restagePointerFile (Restage True) f orig = withTSDelta $ \tsd ->
        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 @@ restagePointerFile (Restage True) f orig = withTSDelta $ \tsd ->
                    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 @@ restagePointerFile (Restage True) f orig = withTSDelta $ \tsd ->
                                                        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
index e1e7000637fe68443c8d43546144865f512b1ce3..99ba18d542e2d14d0df64d09689191a8b82c444c 100644 (file)
@@ -471,8 +471,8 @@ gitAnnexMergeLock :: Git.Repo -> FilePath
 gitAnnexMergeLock r = fromRawFilePath $ gitAnnexDir r P.</> "merge.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.
  -
@@ -482,8 +482,8 @@ 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 -> RawFilePath
index 26e30a147008fb23078e1828b05f1ad7c8735590..7af05044c4fc940657db28a8c94dd5e765cdc7af 100644 (file)
@@ -37,20 +37,20 @@ 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
@@ -67,7 +67,7 @@ setAnnexPerm' modef isdir file = unlessM crippledFileSystem $
                        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,
@@ -78,7 +78,7 @@ resetAnnexFilePerm = resetAnnexPerm False
  - 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
@@ -106,7 +106,7 @@ createAnnexDirectory dir = do
   where
        createdir p = do
                liftIO $ R.createDirectory p
-               setAnnexDirPerm (fromRawFilePath p)
+               setAnnexDirPerm p
 
 {- Create a directory in the git work tree, creating any parent
  - directories up to the top of the work tree.
@@ -131,7 +131,7 @@ createWorkTreeDirectory dir = do
  - 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
@@ -158,7 +158,7 @@ isContentWritePermOk file = ifM crippledFileSystem
                        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
@@ -171,7 +171,7 @@ chmodContent file = unlessM crippledFileSystem $
 
 {- 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
@@ -196,14 +196,14 @@ freezeContentDir :: RawFilePath -> Annex ()
 freezeContentDir file = unlessM crippledFileSystem $
        withShared go
   where
-       dir = fromRawFilePath $ parentDir file
+       dir = parentDir file
        go GroupShared = liftIO $ void $ tryIO $ groupWriteRead dir
        go AllShared = liftIO $ void $ tryIO $ groupWriteRead dir
        go _ = liftIO $ preventWrite dir
 
 thawContentDir :: RawFilePath -> Annex ()
 thawContentDir file = 
-       thawPerms $ liftIO $ allowWrite . fromRawFilePath $ parentDir file
+       thawPerms $ liftIO $ allowWrite $ parentDir file
 
 {- Makes the directory tree to store an annexed file's content,
  - with appropriate permissions on each level. -}
@@ -213,7 +213,7 @@ createContentDir dest = do
                createAnnexDirectory dir 
        -- might have already existed with restricted perms
        unlessM crippledFileSystem $
-               liftIO $ allowWrite $ fromRawFilePath dir
+               liftIO $ allowWrite dir
   where
        dir = parentDir dest
 
index 09c33236097a01f92ed946f6dfe1b8ff253ec7d1..3826f5e70e25538ddffb0294c75519d591ed4b25 100644 (file)
@@ -248,7 +248,7 @@ installSshKeyPair sshkeypair sshdata = do
                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)
 
@@ -331,7 +331,7 @@ setSshConfig sshdata config = do
                        , "Host " ++ mangledhost
                        ] ++ map (\(k, v) -> "\t" ++ k ++ " " ++ v)
                                (settings ++ config)
-               setSshConfigMode configfile
+               setSshConfigMode (toRawFilePath configfile)
 
        return $ sshdata
                { sshHostName = T.pack mangledhost
index e741c8151757f8da6f56a7d8ef759771a0adcac6..6069614e6ecefa0e397ee0165c900f315d541766 100644 (file)
--- a/Common.hs
+++ b/Common.hs
@@ -25,6 +25,7 @@ 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
index 6ab3b81925a4a7b4943458b4db0e780f2788170d..58f1ca1165b69ee4da6cbe7804867c6a4069d67e 100644 (file)
--- a/Creds.hs
+++ b/Creds.hs
@@ -36,6 +36,7 @@ import Utility.Env (getEnv)
 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,7 +191,7 @@ writeCreds :: Creds -> FilePath -> Annex ()
 writeCreds creds file = do
        d <- fromRepo gitAnnexCredsDir
        createAnnexDirectory d
-       liftIO $ writeFileProtected (fromRawFilePath d </> file) creds
+       liftIO $ writeFileProtected (d P.</> toRawFilePath file) creds
 
 readCreds :: FilePath -> Annex (Maybe Creds)
 readCreds f = liftIO . catchMaybeIO . readFileStrict =<< credsFile f
index 5a59ac4164019bd135d5316d43c250942ec16403..9174ac7f09b4bf3c3b72a5fa13ebe104f2d08c39 100644 (file)
@@ -25,12 +25,13 @@ import Criterion.Main
 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,18 +102,18 @@ fileMiss = fileN 0 -- 0 is never stored
 
 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
        h <- liftIO $ H.openDbQueue H.MultiWriter db SQL.containedTable
        liftIO $ populateAssociatedFiles h num
-       sz <- liftIO $ getFileSize (toRawFilePath db)
+       sz <- liftIO $ getFileSize db
        liftIO $ putStrLn $ "size of database on disk: " ++ 
                roughSize storageUnits False sz
        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 */
index a58ebed5bb535c5abf09ef48ae23ff0cf90ed2af..10f97172ac21e4fb1e591fe403577d3382565814 100644 (file)
@@ -47,9 +47,11 @@ import qualified Git.Ref
 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 +77,8 @@ AnnexBranch
 openDb :: Annex ContentIdentifierHandle
 openDb = do
        dbdir <- fromRawFilePath <$> 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"
index 3400bfaf03e407d23940f367ea4c7b2ebe5f6f7b..1eba4dd40181b4a2cc592ee1fdd9d1f21ef57115 100644 (file)
@@ -59,9 +59,11 @@ import Git.Types
 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
 
@@ -96,9 +98,9 @@ ExportTreeCurrent
  -}
 openDb :: UUID -> Annex ExportHandle
 openDb u = do
-       dbdir <- fromRawFilePath <$> fromRepo (gitAnnexExportDbDir u)
-       let db = dbdir </> "db"
-       unlessM (liftIO $ doesFileExist db) $ do
+       dbdir <- fromRepo (gitAnnexExportDbDir u)
+       let db = dbdir P.</> "db"
+       unlessM (liftIO $ R.doesPathExist db) $ do
                initDb db $ void $
                        runMigrationSilent migrateExport
        h <- liftIO $ H.openDbQueue H.SingleWriter db "exported"
index fb1a2791a8b08cc70191d2aa9e2c99e076cd5b6a..528f3a00788b695f114b9b9c27445a5ffcb32037 100644 (file)
@@ -33,10 +33,12 @@ import Annex.Locations
 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
 
@@ -68,8 +70,8 @@ newPass u = isJust <$> tryExclusiveLock (gitAnnexFsckDbLock u) go
 openDb :: UUID -> Annex FsckHandle
 openDb u = do
        dbdir <- fromRepo (gitAnnexFsckDbDir u)
-       let db = fromRawFilePath 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)
index 4422d9e756fe8229e5bb28a51a196a96d5e6f901..2109ad9ac528b36dc86c22a330772ef8c37c9187 100644 (file)
@@ -63,10 +63,10 @@ data DbConcurrency = SingleWriter | MultiWriter
 
 {- 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
index c610d24aa3f00b95d29f6af85e5c14cf142e6736..3f67093bd51116faf4f7a6b89528d6d61047e6cf 100644 (file)
@@ -5,16 +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.
@@ -24,24 +28,24 @@ import Lens.Micro
  - 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
+       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 (toRawFilePath tmpdbdir)
+               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.
index 27834af611591d74521234e9bc0ce3fedcee52db..6b305f060cf45f05923cffb0562f0acc0f1f72a2 100644 (file)
@@ -43,6 +43,7 @@ import Git.FilePath
 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 _ st@(DbOpen _) = return st
 openDb False DbUnavailable = return DbUnavailable
 openDb createdb _ = catchPermissionDenied permerr $ withExclusiveLock gitAnnexKeysDbLock $ do
        dbdir <- fromRepo gitAnnexKeysDb
-       let db = fromRawFilePath 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
@@ -215,7 +216,7 @@ reconcileStaged :: H.DbQueue -> Annex ()
 reconcileStaged qh = do
        gitindex <- inRepo currentIndexFile
        indexcache <- fromRawFilePath <$> fromRepo gitAnnexKeysDbIndexCache
-       withTSDelta (liftIO . genInodeCache (toRawFilePath gitindex)) >>= \case
+       withTSDelta (liftIO . genInodeCache gitindex) >>= \case
                Just cur -> 
                        liftIO (maybe Nothing readInodeCache <$> catchMaybeIO (readFile indexcache)) >>= \case
                                Nothing -> go cur indexcache
index 0ed4d161a49e26aaf570264f095ae46abfdca182..68e3e42f87a5c98a3fde6a4a2adc512d6285e453 100644 (file)
@@ -19,6 +19,7 @@ module Database.Queue (
 ) where
 
 import Utility.Monad
+import Utility.RawFilePath
 import Database.Handle
 
 import Database.Persist.Sqlite
@@ -36,7 +37,7 @@ data DbQueue = DQ DbHandle (MVar Queue)
 {- 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)
index c946015cfe2494953a83d3e4ec41424df164780a..b55fc04b997e394bcdc0adcfd700e54bb6b5c9b0 100644 (file)
@@ -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 Git
 import Utility.Env
 import Utility.Env.Set
 
+import qualified System.FilePath.ByteString as P
+
 indexEnv :: String
 indexEnv = "GIT_INDEX_FILE"
 
@@ -26,8 +30,8 @@ indexEnv = "GIT_INDEX_FILE"
  -
  - So, an absolute path is the only safe option for this to return.
  -}
-indexEnvVal :: FilePath -> IO String
-indexEnvVal p = fromRawFilePath <$> absPath (toRawFilePath p)
+indexEnvVal :: RawFilePath -> IO String
+indexEnvVal p = fromRawFilePath <$> absPath p
 
 {- Forces git to use the specified index file.
  -
@@ -36,7 +40,7 @@ indexEnvVal p = fromRawFilePath <$> absPath (toRawFilePath p)
  -
  - 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 @@ override index _r = do
        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"
index 6a240875e09c7b67e010f784334a610452f58dd2..9b7165c0ad5c1085d1cebb081052ac103f69c87e 100644 (file)
@@ -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
+
+objectsDir :: Repo -> RawFilePath
+objectsDir r = localGitDir r P.</> "objects"
 
-packDir :: Repo -> FilePath
-packDir r = objectsDir r </> "pack"
+packDir :: Repo -> RawFilePath
+packDir r = objectsDir r P.</> "pack"
 
-packIdxFile :: FilePath -> FilePath
-packIdxFile = flip replaceExtension "idx"
+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. -}
index eb8736a0117e51b1e459f3e8d2c45afa8fe31336..45d9d7c4897d5fde5969ab1c4c7c228c9849f2ad 100644 (file)
@@ -53,9 +53,9 @@ cleanCorruptObjects fsckresults r = do
        mapM_ removeLoose (S.toList $ knownMissing fsckresults)
        mapM_ removeBad =<< listLooseObjectShas r
   where
-       removeLoose s = removeWhenExistsWith removeLink (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
 
@@ -79,10 +79,11 @@ explodePacks r = go =<< listPackFiles r
                putStrLn "Unpacking all pack files."
                forM_ packs $ \packfile -> do
                        moveFile packfile (tmpdir </> takeFileName packfile)
-                       removeWhenExistsWith removeLink $ 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 ->
@@ -163,8 +164,8 @@ retrieveMissingObjects missing referencerepo r
 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
@@ -395,7 +396,7 @@ rewriteIndex r
        | otherwise = do
                (bad, good, cleanup) <- partitionIndex r
                unless (null bad) $ do
-                       removeWhenExistsWith removeLink (indexFile r)
+                       removeWhenExistsWith R.removeLink (indexFile r)
                        UpdateIndex.streamUpdateIndex r
                                =<< (catMaybes <$> mapM reinject good)
                void cleanup
@@ -446,9 +447,8 @@ preRepair g = do
                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
@@ -572,7 +572,7 @@ runRepair' removablebranch fsckresult forced referencerepo g = do
                        else successfulfinish modifiedbranches
 
        corruptedindex = do
-               removeWhenExistsWith removeLink (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
@@ -618,5 +618,5 @@ successfulRepair = fst
 
 safeReadFile :: FilePath -> IO String
 safeReadFile f = do
-       allowRead f
+       allowRead (toRawFilePath f)
        readFileStrict f
index 32162f75253b13c0e554edecbf1e7ca39c9c2406..c62f16ce6d016dc569fe3f704e6291b4f464fc73 100644 (file)
@@ -32,9 +32,9 @@ import qualified Data.ByteString.Lazy.Char8 as L8
 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.
@@ -45,7 +45,7 @@ withLogHandle f a = do
                bracket (setup tmp) cleanup a
   where
        setup tmp = do
-               setAnnexFilePerm tmp
+               setAnnexFilePerm (toRawFilePath tmp)
                liftIO $ openFile tmp WriteMode
        cleanup h = liftIO $ hClose h
 
@@ -57,7 +57,7 @@ appendLogFile f lck c =
                withExclusiveLock lck $ do
                        liftIO $ withFile f' AppendMode $
                                \h -> L8.hPutStrLn h c
-                       setAnnexFilePerm f'
+                       setAnnexFilePerm (toRawFilePath f')
   where
        f' = fromRawFilePath f
 
@@ -81,7 +81,7 @@ modifyLogFile f lck modf = withExclusiveLock lck $ do
        f' = fromRawFilePath f
        writelog lf b = do
                liftIO $ L.writeFile lf b
-               setAnnexFilePerm lf
+               setAnnexFilePerm (toRawFilePath lf)
 
 -- | Checks the content of a log file to see if any line matches.
 --
@@ -134,7 +134,7 @@ streamLogFile f lck a = withExclusiveLock lck $ bracketOnError setup cleanup go
                mapM_ a =<< liftIO (lines <$> hGetContents h)
                liftIO $ hClose h
                liftIO $ writeFile f ""
-               setAnnexFilePerm f
+               setAnnexFilePerm (toRawFilePath f)
 
 createDirWhenNeeded :: RawFilePath -> Annex () -> Annex ()
 createDirWhenNeeded f a = a `catchNonAsync` \_e -> do
index 43075546bcd10df4b3c268ac2b15fd0302c7cb9d..11aa8deca0d4714e2c8c4ee03009d51b27d72bd6 100644 (file)
--- a/P2P/IO.hs
+++ b/P2P/IO.hs
@@ -135,7 +135,7 @@ serveUnixSocket unixsocket serveconn = do
         -- 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
index b839352e246886119a4310ff63c2bcc0df2864ff..54ca7186b6b28663ca578efa8d2c6646edf30286 100644 (file)
@@ -18,18 +18,11 @@ import Control.Monad
 import System.FilePath
 import System.PosixCompat.Files
 import Control.Applicative
-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.Tmp
 import Utility.Exception
 import Utility.Monad
 import Utility.Applicative
@@ -98,50 +91,6 @@ dirTreeRecursiveSkipping skipdir topdir = go [] [topdir]
                                =<< 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
-
 {- Use with an action that removes something, which may or may not exist.
  -
  - If an exception is thrown due to it not existing, it is ignored.
index 352c3c19a58304a07308cfca98ab7f3b0ee32076..03e838e8a5ba331fedc145fa025ee223ccdbf3e7 100644 (file)
@@ -22,22 +22,24 @@ import Foreign (complement)
 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 @@ otherGroupModes =
        ]
 
 {- 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 @@ groupSharedModes =
        , ownerReadMode, groupReadMode
        ]
 
-groupWriteRead :: FilePath -> IO ()
+groupWriteRead :: RawFilePath -> IO ()
 groupWriteRead f = modifyFileMode f $ addModes groupSharedModes
 
 checkMode :: FileMode -> FileMode -> Bool
@@ -149,7 +151,7 @@ isSticky = checkMode stickyMode
 stickyMode :: FileMode
 stickyMode = 512
 
-setSticky :: FilePath -> IO ()
+setSticky :: RawFilePath -> IO ()
 setSticky f = modifyFileMode f $ addModes [stickyMode]
 #endif
 
@@ -162,13 +164,13 @@ setSticky f = modifyFileMode f $ addModes [stickyMode]
  - 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
 
index e5796dd55a3b68c7fd54f9a271ffb805d5a18279..b705bb599ac59558e710e3741a511d2e8763bd80 100644 (file)
@@ -422,7 +422,7 @@ testHarness tmpdir cmd a = ifM (inPath (unGpgCmd cmd))
                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.
diff --git a/Utility/MoveFile.hs b/Utility/MoveFile.hs
new file mode 100644 (file)
index 0000000..695ed03
--- /dev/null
@@ -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
index f5fff2a40ec960bb28d407e318f6f884769bfb59..79b0545f48bf6a0584d68ba8ea9c7e54aa9a0ec5 100644 (file)
@@ -25,6 +25,7 @@ module Utility.RawFilePath (
        doesPathExist,
        getCurrentDirectory,
        createDirectory,
+       setFileMode,
 ) where
 
 #ifndef mingw32_HOST_OS
@@ -45,8 +46,9 @@ 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
 
@@ -80,4 +82,7 @@ getCurrentDirectory = toRawFilePath <$> D.getCurrentDirectory
 
 createDirectory :: RawFilePath -> IO ()
 createDirectory = D.createDirectory . fromRawFilePath
+
+setFileMode :: RawFilePath -> FileMode -> IO () 
+setFileMode = F.setFileMode
 #endif
index 111d73ec440843642665c31267e181e13bae48d1..bac38c530ffb64e608bded1e934a3abe8193f230 100644 (file)
@@ -144,7 +144,7 @@ changeUserSshConfig modifier = do
 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 @@ writeSshConfig f s = do
  - 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]
 
index 168e6448dcd6e3f600869fcb65b71284e712a134..13a019e2b69068ef7d7481288251fefea1df607c 100644 (file)
@@ -166,7 +166,7 @@ prepHiddenServiceSocketDir :: AppName -> UserID -> UniqueIdent -> IO ()
 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
index 8e89517a6c64e3bff8cba7d356c8303222a6fe77..4bbec201a94fe3279f1690196b44e9b75e6ce6f1 100644 (file)
@@ -189,7 +189,8 @@ insertAuthToken extractAuthToken predicate webapp root pathbits params =
 {- 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
index ed0cef06cd1996c38614a9f0727770240b896ead..3ed8619145b243e2219ecf1b764547f64697e750 100644 (file)
@@ -1090,6 +1090,7 @@ Executable git-annex
     Utility.Metered
     Utility.Misc
     Utility.Monad
+    Utility.MoveFile
     Utility.Network
     Utility.NotificationBroadcaster
     Utility.OptParse