handle edge case of symlink to something that is not really a pointer file

That seems very unlikely to happen, but still, it's possible it could.
And with the recent addition of locked files to the keys db, this could
be called by places that did not call it before, so it seems even more
important it's correct.

Adds an extra stat of the file, and is potentially racy, but both
problems are fixed by the unix-2.8.0 path. I have not tested that path
builds because that package is not yet released and it would be difficult
to install it since it's tightly tied to a ghc version.
This commit is contained in:
Joey Hess 2021-06-14 11:29:49 -04:00
parent 673b2feaf3
commit 26a9ea12d1
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38

View file

@ -7,7 +7,7 @@
-
- Pointer files are used instead of symlinks for unlocked files.
-
- Copyright 2013-2019 Joey Hess <id@joeyh.name>
- Copyright 2013-2021 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
@ -294,10 +294,36 @@ unpaddedMaxPointerSz = 8192
{- Checks if a worktree file is a pointer to a key.
-
- Unlocked files whose content is present are not detected by this. -}
- Unlocked files whose content is present are not detected by this.
-
- It's possible, though unlikely, that an annex symlink points to
- an object that looks like a pointer file. Or that a non-annex
- symlink does. Avoids a false positive in those cases.
- -}
isPointerFile :: RawFilePath -> IO (Maybe Key)
isPointerFile f = catchDefaultIO Nothing $ withFile (fromRawFilePath f) ReadMode $ \h ->
parseLinkTargetOrPointer <$> S.hGet h unpaddedMaxPointerSz
isPointerFile f = catchDefaultIO Nothing $ do
#if defined(mingw32_HOST_OS)
checkcontentfollowssymlinks -- no symlinks supported on windows
#else
#if MIN_VERSION_unix(2,8,0)
bracket
(openFd (fromRawFilePath f) ReadOnly (defaultFileFlags { nofollow = True }) Nothing)
closeFd
(\fd -> readhandle =<< fdToHandle fd)
#else
pointercontent <- checkcontentfollowssymlinks
if isJust pointercontent
then ifM (isSymbolicLink <$> R.getSymbolicLinkStatus f)
( return Nothing
, return pointercontent
)
else return Nothing
#endif
#endif
where
checkcontentfollowssymlinks =
withFile (fromRawFilePath f) ReadMode readhandle
readhandle h = parseLinkTargetOrPointer <$> S.hGet h unpaddedMaxPointerSz
{- Checks a symlink target or pointer file first line to see if it
- appears to point to annexed content.