use getSymbolicLinkStatus not getFileStatus to avoid crash on broken symlink

Fix crash importing from a directory special remote that contains a broken
symlink.

The crash was in listImportableContentsM but some other places in
Remote.Directory also seemed like they could have the same problem.

Also audited for other places that have such a problem. Not all calls
to getFileStatus are bad, in some cases it's better to crash on something
unexpected. For example, `git-annex import path` when the path is a broken
symlink should crash, the same as when it does not exist. Many of the
getFileStatus calls are like that, particularly when they involve
.git/annex/objects which should never have a broken symlink in it.

Fixed a few other possible cases of the problem.

Sponsored-by: Lawrence Brogan on Patreon
This commit is contained in:
Joey Hess 2022-09-05 13:44:03 -04:00
parent 600d3f7141
commit 8a4cfd4f2d
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
10 changed files with 26 additions and 15 deletions

View file

@ -218,8 +218,8 @@ checkDiskSpaceDirectory d k = do
annexdir <- fromRepo gitAnnexObjectDir
samefilesystem <- liftIO $ catchDefaultIO False $
(\a b -> deviceID a == deviceID b)
<$> R.getFileStatus d
<*> R.getFileStatus annexdir
<$> R.getSymbolicLinkStatus d
<*> R.getSymbolicLinkStatus annexdir
checkDiskSpace (Just d) k 0 samefilesystem
{- Passed a temp directory that contains the files that should be placed
@ -369,7 +369,7 @@ listImportableContentsM ii dir = liftIO $ do
ImportableContents (catMaybes l') []
where
go f = do
st <- R.getFileStatus f
st <- R.getSymbolicLinkStatus f
mkContentIdentifier ii f st >>= \case
Nothing -> return Nothing
Just cid -> do
@ -402,7 +402,7 @@ importKeyM ii dir loc cid sz p = do
let k = alterKey unsizedk $ \kd -> kd
{ keySize = keySize kd <|> Just sz }
currcid <- liftIO $ mkContentIdentifier ii absf
=<< R.getFileStatus absf
=<< R.getSymbolicLinkStatus absf
guardSameContentIdentifiers (return (Just k)) cid currcid
where
f = fromExportLocation loc
@ -462,7 +462,7 @@ retrieveExportWithContentIdentifierM ii dir cow loc cid dest gk p =
-- content.
precheck cont = guardSameContentIdentifiers cont cid
=<< liftIO . mkContentIdentifier ii f
=<< liftIO (R.getFileStatus f)
=<< liftIO (R.getSymbolicLinkStatus f)
-- Check after copy, in case the file was changed while it was
-- being copied.
@ -486,7 +486,7 @@ retrieveExportWithContentIdentifierM ii dir cow loc cid dest gk p =
#ifndef mingw32_HOST_OS
=<< getFdStatus fd
#else
=<< R.getFileStatus f
=<< R.getSymbolicLinkStatus f
#endif
guardSameContentIdentifiers cont cid currcid
@ -497,7 +497,7 @@ retrieveExportWithContentIdentifierM ii dir cow loc cid dest gk p =
-- restored to the original content before this check.
postcheckcow cont = do
currcid <- liftIO $ mkContentIdentifier ii f
=<< R.getFileStatus f
=<< R.getSymbolicLinkStatus f
guardSameContentIdentifiers cont cid currcid
storeExportWithContentIdentifierM :: IgnoreInodes -> RawFilePath -> CopyCoWTried -> FilePath -> Key -> ExportLocation -> [ContentIdentifier] -> MeterUpdate -> Annex ContentIdentifier
@ -508,7 +508,7 @@ storeExportWithContentIdentifierM ii dir cow src _k loc overwritablecids p = do
void $ liftIO $ fileCopier cow src tmpf p Nothing
let tmpf' = toRawFilePath tmpf
resetAnnexFilePerm tmpf'
liftIO (getFileStatus tmpf) >>= liftIO . mkContentIdentifier ii tmpf' >>= \case
liftIO (getSymbolicLinkStatus tmpf) >>= liftIO . mkContentIdentifier ii tmpf' >>= \case
Nothing -> giveup "unable to generate content identifier"
Just newcid -> do
checkExportContent ii dir loc
@ -553,7 +553,7 @@ data CheckResult = DoesNotExist | KnownContentIdentifier
-- content is known, and immediately run the callback.
checkExportContent :: IgnoreInodes -> RawFilePath -> ExportLocation -> [ContentIdentifier] -> Annex a -> (CheckResult -> Annex a) -> Annex a
checkExportContent ii dir loc knowncids unsafe callback =
tryWhenExists (liftIO $ R.getFileStatus dest) >>= \case
tryWhenExists (liftIO $ R.getSymbolicLinkStatus dest) >>= \case
Just destst
| not (isRegularFile destst) -> unsafe
| otherwise -> catchDefaultIO Nothing (liftIO $ mkContentIdentifier ii dest destst) >>= \case