stop symlink check once the top of the working tree is reached

Avoid complaining that a file with "is beyond a symbolic link" when the
filepath is absolute and the symlink in question is not actually inside the
git repository.

This assumes that inodes remain stable while the command is running.
I think they always will, the filesystems where they are unstable change
them across mounts. (If inodes were not stable, it would just complain about
symlinks in the path that are not inside the working tree.)

(On windows, I don't want to assume anything about inodes, they could be
random numbers for all I know. But if they were, this would still be ok, as
long as windows doesn't have symlinks that are detected by isSymbolicLink.
Which seems a fair bet.)
This commit is contained in:
Joey Hess 2020-08-06 20:14:30 -04:00
parent a358eb1faa
commit 506ffea5e6
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
4 changed files with 38 additions and 7 deletions

View file

@ -20,6 +20,9 @@ git-annex (8.20200720.2) UNRELEASED; urgency=medium
* Slightly sped up the linux standalone bundle.
* importfeed: Fix reversion that caused some '.' in filenames to be
replaced with '_'
* Avoid complaining that a file with "is beyond a symbolic link"
when the filepath is absolute and the symlink in question is not
actually inside the git repository.
-- Joey Hess <id@joeyh.name> Tue, 21 Jul 2020 12:58:30 -0400

View file

@ -445,11 +445,12 @@ workTreeItems' (AllowHidden allowhidden) ww ps = case ww of
where
runcheck = do
currbranch <- getCurrentBranch
stopattop <- prepviasymlink
ps' <- flip filterM ps $ \p -> do
relf <- liftIO $ relPathCwdToFile p
ifM (not <$> (exists p <||> hidden currbranch relf))
( prob (p ++ " not found")
, ifM (viasymlink (upFrom relf))
, ifM (viasymlink stopattop (upFrom relf))
( prob (p ++ " is beyond a symbolic link")
, return True
)
@ -460,12 +461,25 @@ workTreeItems' (AllowHidden allowhidden) ww ps = case ww of
exists p = isJust <$> liftIO (catchMaybeIO $ getSymbolicLinkStatus p)
viasymlink Nothing = return False
viasymlink (Just p) =
ifM (liftIO $ isSymbolicLink <$> getSymbolicLinkStatus p)
( return True
, viasymlink (upFrom p)
)
prepviasymlink = do
repotopst <- inRepo $
maybe
(pure Nothing)
(catchMaybeIO . R.getSymbolicLinkStatus)
. Git.repoWorkTree
return $ \st -> case repotopst of
Nothing -> False
Just tst -> fileID st == fileID tst
&& deviceID st == deviceID tst
viasymlink _ Nothing = return False
viasymlink stopattop (Just p) = do
st <- liftIO $ getSymbolicLinkStatus p
if stopattop st
then return False
else if isSymbolicLink st
then return True
else viasymlink stopattop (upFrom p)
hidden currbranch f
| allowhidden = isJust

View file

@ -77,3 +77,5 @@ caller's side, but since it looks like an unintended consequence of
[[!meta author=kyle]]
[[!tag projects/datalad]]
> [[fixed|done]] --[[Joey]]

View file

@ -0,0 +1,12 @@
[[!comment format=mdwn
username="joey"
subject="""comment 3"""
date="2020-08-06T22:29:49Z"
content="""
AFAICS, git does something like cache the stat of the directory at the top
of the working tree, and uses that to know which part to check for symlinks.
There's a lstat cache in the relevant code anyway.
Ok, implemented it that way in git-annex, which I was able to do w/o doing
any more work per file than comparing a dev and an inode.
"""]]