avoid unix-compat's rename

On Windows, that does not support long paths
https://github.com/jacobstanley/unix-compat/issues/56

Instead, use System.Directory.renamePath, which does support long paths.

Sponsored-by: Dartmouth College's Datalad project
This commit is contained in:
Joey Hess 2022-07-12 14:53:32 -04:00
parent bad39cadc6
commit 2d65c4ff1d
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
18 changed files with 75 additions and 20 deletions

View file

@ -207,13 +207,13 @@ upgradeToDistribution newdir cleanup distributionfile = do
unless tarok $ unless tarok $
error $ "failed to untar " ++ distributionfile error $ "failed to untar " ++ distributionfile
sanitycheck $ tmpdir </> installBase sanitycheck $ tmpdir </> installBase
installby rename newdir (tmpdir </> installBase) installby R.rename newdir (tmpdir </> installBase)
let deleteold = do let deleteold = do
deleteFromManifest olddir deleteFromManifest olddir
makeorigsymlink olddir makeorigsymlink olddir
return (newdir </> "git-annex", deleteold) return (newdir </> "git-annex", deleteold)
installby a dstdir srcdir = installby a dstdir srcdir =
mapM_ (\x -> a x (dstdir </> takeFileName x)) mapM_ (\x -> a (toRawFilePath x) (toRawFilePath (dstdir </> takeFileName x)))
=<< dirContents srcdir =<< dirContents srcdir
#endif #endif
sanitycheck dir = sanitycheck dir =

View file

@ -30,7 +30,7 @@ import Annex.CheckIgnore
import qualified Utility.RawFilePath as R import qualified Utility.RawFilePath as R
import qualified System.FilePath.ByteString as P import qualified System.FilePath.ByteString as P
import System.PosixCompat.Files import System.PosixCompat.Files (fileSize)
cmd :: Command cmd :: Command
cmd = notBareRepo $ cmd = notBareRepo $

View file

@ -181,11 +181,11 @@ runFuzzAction (FuzzAdd (FuzzFile f)) = do
runFuzzAction (FuzzDelete (FuzzFile f)) = liftIO $ runFuzzAction (FuzzDelete (FuzzFile f)) = liftIO $
removeWhenExistsWith R.removeLink (toRawFilePath f) removeWhenExistsWith R.removeLink (toRawFilePath f)
runFuzzAction (FuzzMove (FuzzFile src) (FuzzFile dest)) = liftIO $ runFuzzAction (FuzzMove (FuzzFile src) (FuzzFile dest)) = liftIO $
rename src dest R.rename (toRawFilePath src) (toRawFilePath dest)
runFuzzAction (FuzzDeleteDir (FuzzDir d)) = liftIO $ runFuzzAction (FuzzDeleteDir (FuzzDir d)) = liftIO $
removeDirectoryRecursive d removeDirectoryRecursive d
runFuzzAction (FuzzMoveDir (FuzzDir src) (FuzzDir dest)) = liftIO $ runFuzzAction (FuzzMoveDir (FuzzDir src) (FuzzDir dest)) = liftIO $
rename src dest R.rename (toRawFilePath src) (toRawFilePath dest)
runFuzzAction (FuzzPause d) = randomDelay d runFuzzAction (FuzzPause d) = randomDelay d
genFuzzAction :: Annex FuzzAction genFuzzAction :: Annex FuzzAction

View file

@ -216,7 +216,7 @@ storeReceived f = do
Just k -> void $ logStatusAfter k $ Just k -> void $ logStatusAfter k $
getViaTmpFromDisk RetrievalVerifiableKeysSecure AlwaysVerify k (AssociatedFile Nothing) $ \dest -> unVerified $ getViaTmpFromDisk RetrievalVerifiableKeysSecure AlwaysVerify k (AssociatedFile Nothing) $ \dest -> unVerified $
liftIO $ catchBoolIO $ do liftIO $ catchBoolIO $ do
rename f (fromRawFilePath dest) R.rename (toRawFilePath f) dest
return True return True
-- Under Windows, uftp uses key containers, which are not files on the -- Under Windows, uftp uses key containers, which are not files on the

View file

@ -13,7 +13,7 @@ import Data.Default as X
import System.FilePath as X import System.FilePath as X
import System.IO as X hiding (FilePath) import System.IO as X hiding (FilePath)
import System.Exit as X import System.Exit as X
import System.PosixCompat.Files as X hiding (fileSize, removeLink) import System.PosixCompat.Files as X hiding (fileSize, removeLink, rename)
import Utility.Misc as X import Utility.Misc as X
import Utility.Exception as X import Utility.Exception as X

View file

@ -45,7 +45,7 @@ initDb db migration = do
setAnnexFilePerm tmpdb setAnnexFilePerm tmpdb
liftIO $ do liftIO $ do
void $ tryIO $ removeDirectoryRecursive (fromRawFilePath dbdir) void $ tryIO $ removeDirectoryRecursive (fromRawFilePath dbdir)
rename (fromRawFilePath tmpdbdir) (fromRawFilePath dbdir) R.rename tmpdbdir dbdir
{- Make sure that the database uses WAL mode, to prevent readers {- Make sure that the database uses WAL mode, to prevent readers
- from blocking writers, and prevent a writer from blocking readers. - from blocking writers, and prevent a writer from blocking readers.

View file

@ -514,11 +514,11 @@ storeExportWithContentIdentifierM ii dir cow src _k loc overwritablecids p = do
checkExportContent ii dir loc checkExportContent ii dir loc
overwritablecids overwritablecids
(giveup "unsafe to overwrite file") (giveup "unsafe to overwrite file")
(const $ liftIO $ rename tmpf dest) (const $ liftIO $ R.rename tmpf' dest)
return newcid return newcid
where where
dest = fromRawFilePath $ exportPath dir loc dest = exportPath dir loc
(destdir, base) = splitFileName dest (destdir, base) = splitFileName (fromRawFilePath dest)
template = relatedTemplate (base ++ ".tmp") template = relatedTemplate (base ++ ".tmp")
removeExportWithContentIdentifierM :: IgnoreInodes -> RawFilePath -> Key -> ExportLocation -> [ContentIdentifier] -> Annex () removeExportWithContentIdentifierM :: IgnoreInodes -> RawFilePath -> Key -> ExportLocation -> [ContentIdentifier] -> Annex ()

View file

@ -47,6 +47,7 @@ import Utility.Tmp.Dir
import Utility.SshHost import Utility.SshHost
import Annex.SpecialRemote.Config import Annex.SpecialRemote.Config
import Annex.Verify import Annex.Verify
import qualified Utility.RawFilePath as R
import qualified Data.Map as M import qualified Data.Map as M
@ -224,7 +225,7 @@ store o k src meterupdate = storeGeneric o meterupdate basedest populatedest
basedest = fromRawFilePath $ Prelude.head (keyPaths k) basedest = fromRawFilePath $ Prelude.head (keyPaths k)
populatedest dest = liftIO $ if canrename populatedest dest = liftIO $ if canrename
then do then do
rename src dest R.rename (toRawFilePath src) (toRawFilePath dest)
return True return True
else createLinkOrCopy (toRawFilePath src) (toRawFilePath dest) else createLinkOrCopy (toRawFilePath src) (toRawFilePath dest)
{- If the key being sent is encrypted or chunked, the file {- If the key being sent is encrypted or chunked, the file

View file

@ -16,7 +16,7 @@ module Utility.Directory (
import Control.Monad import Control.Monad
import System.FilePath import System.FilePath
import System.PosixCompat.Files hiding (removeLink) import System.PosixCompat.Files (getSymbolicLinkStatus, isDirectory, isSymbolicLink)
import Control.Applicative import Control.Applicative
import System.IO.Unsafe (unsafeInterleaveIO) import System.IO.Unsafe (unsafeInterleaveIO)
import Data.Maybe import Data.Maybe

View file

@ -16,7 +16,7 @@ module Utility.FileMode (
import System.IO import System.IO
import Control.Monad import Control.Monad
import System.PosixCompat.Types import System.PosixCompat.Types
import System.PosixCompat.Files hiding (removeLink) import System.PosixCompat.Files (unionFileModes, intersectFileModes, stdFileMode, nullFileMode, setFileCreationMask, groupReadMode, ownerReadMode, ownerWriteMode, ownerExecuteMode, groupWriteMode, groupExecuteMode, otherReadMode, otherWriteMode, otherExecuteMode, fileMode)
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Foreign (complement) import Foreign (complement)
import Control.Monad.Catch import Control.Monad.Catch

View file

@ -14,7 +14,7 @@ module Utility.FileSize (
getFileSize', getFileSize',
) where ) where
import System.PosixCompat.Files hiding (removeLink) import System.PosixCompat.Files (FileStatus, fileSize)
import qualified Utility.RawFilePath as R import qualified Utility.RawFilePath as R
#ifdef mingw32_HOST_OS #ifdef mingw32_HOST_OS
import Control.Exception (bracket) import Control.Exception (bracket)

View file

@ -18,6 +18,7 @@ module Utility.LogFile (
) where ) where
import Common import Common
import Utility.RawFilePath
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
import System.Posix.Types import System.Posix.Types
@ -36,7 +37,7 @@ rotateLog logfile = go 0
| num > maxLogs = return () | num > maxLogs = return ()
| otherwise = whenM (doesFileExist currfile) $ do | otherwise = whenM (doesFileExist currfile) $ do
go (num + 1) go (num + 1)
rename currfile nextfile rename (toRawFilePath currfile) (toRawFilePath nextfile)
where where
currfile = filename num currfile = filename num
nextfile = filename (num + 1) nextfile = filename (num + 1)

View file

@ -89,6 +89,8 @@ createDirectory = D.createDirectory . fromRawFilePath
setFileMode :: RawFilePath -> FileMode -> IO () setFileMode :: RawFilePath -> FileMode -> IO ()
setFileMode = F.setFileMode . fromRawFilePath setFileMode = F.setFileMode . fromRawFilePath
{- Using renamePath rather than the rename provided in unix-compat
- because of this bug https://github.com/jacobstanley/unix-compat/issues/56-}
rename :: RawFilePath -> RawFilePath -> IO () rename :: RawFilePath -> RawFilePath -> IO ()
rename a b = F.rename (fromRawFilePath a) (fromRawFilePath b) rename a b = D.renamePath (fromRawFilePath a) (fromRawFilePath b)
#endif #endif

View file

@ -21,7 +21,7 @@ import Utility.Data
import Control.Applicative import Control.Applicative
#endif #endif
import System.PosixCompat import System.PosixCompat.User
import Prelude import Prelude
{- Current user's home directory. {- Current user's home directory.

View file

@ -33,3 +33,5 @@ CI used
### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders) ### Have you had any luck using git-annex before? (Sometimes we get tired of reading bug reports all day and a lil' positive end note does wonders)
All the time! Sorry to mostly show up when there is an issue! All the time! Sorry to mostly show up when there is an issue!
[[!tag projects/datalad]]

View file

@ -0,0 +1,24 @@
[[!comment format=mdwn
username="joey"
subject="""comment 2"""
date="2022-07-12T16:50:16Z"
content="""
Actually testremote will not accept --backend in current master, since that
is no longer a global option and is accepted only by commands that can
actually use it.
testremote cannot support an arbitrary backend here, because it needs to
generate a test key that cannot possibly be used for real data. The only
backend that has a way implemented to do that is SHA256. It would not,
for example, be possible to make the WORM backend support that, since every
possible WORM key could be used by real data.
It would be possible to add support for --backend=MD5 and have it reject
other backends. But this does not strike me as solving the real problem.
Also, in [[bugs/tests_fail_on_windows__58___retrieveKeyFile_resume]]
I ran into this same problem, when `git-annex test` was ran, and
worked around it by disabling that part of the test suite on windows.
If this is fixed, it would be worth re-enabling that, although it may have
also been failing for other reasons on windows.
"""]]

View file

@ -0,0 +1,24 @@
[[!comment format=mdwn
username="joey"
subject="""comment 3"""
date="2022-07-12T17:42:51Z"
content="""
ghc's IO manager tries to support Windows long paths by normalizing to
an UNC-style path in many system calls. However, when git-annex calls
rename, on windows that ends up in Win32's moveFileEx (via unix-compat),
and that does not do UNC-style normalization. And given the description of
the Win32 package, I think it's intended to pass data directly through
to the API without anything fancy.
System.Directory.renamePath could be used instead of Win32.
While it still uses Win32 moveFileEx, it first does an UNC-style
normalization. Filed an issue:
<https://github.com/jacobstanley/unix-compat/issues/56>
Rather than waiting for that to be fixed, I've made git-annex
use System.Directory.renamePath instead itself. But I don't know
if it will be enough to make testremote work, or if it will fall over
on a later operation on the same too-long path.
getFileStatus/getSymbolicLinkStatus seem like the main things in
unix-compat that would still be a problem.
"""]]

View file

@ -294,10 +294,11 @@ source-repository head
custom-setup custom-setup
Setup-Depends: base (>= 4.11.1.0), split, unix-compat, Setup-Depends: base (>= 4.11.1.0), split, unix-compat,
filepath, exceptions, bytestring, directory, IfElse, data-default, filepath, exceptions, bytestring, IfElse, data-default,
filepath-bytestring (>= 1.4.2.1.4), filepath-bytestring (>= 1.4.2.1.4),
process (>= 1.6.3), process (>= 1.6.3),
time (>= 1.5.0), time (>= 1.5.0),
directory (>= 1.2.7.0),
async, utf8-string, transformers, Cabal async, utf8-string, transformers, Cabal
Executable git-annex Executable git-annex
@ -319,7 +320,7 @@ Executable git-annex
unix-compat (>= 0.5), unix-compat (>= 0.5),
SafeSemaphore, SafeSemaphore,
async, async,
directory (>= 1.2), directory (>= 1.2.7.0),
disk-free-space, disk-free-space,
filepath, filepath,
filepath-bytestring (>= 1.4.2.1.1), filepath-bytestring (>= 1.4.2.1.1),