diff --git a/CHANGELOG b/CHANGELOG index 3062587c12..ba6ec9bba1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,8 @@ git-annex (8.20200502) UNRELEASED; urgency=medium without any sanitization, but will fail if the filename has an obvious security problem like using an escape sequence or trying to escape the current directory. + * Display a warning message when asked to operate on a file inside a + directory that's a symbolic link to elsewhere. -- Joey Hess Mon, 04 May 2020 12:46:11 -0400 diff --git a/CmdLine/Seek.hs b/CmdLine/Seek.hs index 6f035fdcb8..77c3bd0e2e 100644 --- a/CmdLine/Seek.hs +++ b/CmdLine/Seek.hs @@ -243,28 +243,47 @@ newtype WorkTreeItem = WorkTreeItem FilePath -- seeking for such files. newtype AllowHidden = AllowHidden Bool --- Many git commands seek work tree items matching some criteria, +-- Many git commands like ls-files seek work tree items matching some criteria, -- and silently skip over anything that does not exist. But users expect -- an error message when one of the files they provided as a command-line -- parameter doesn't exist, so this checks that each exists. +-- +-- Also, when two directories are symlinked, referring to a file +-- inside the symlinked directory will be silently skipped by git commands +-- like ls-files. But, the user would be surprised for it to be skipped, so +-- check if the parent directories are symlinks. workTreeItems :: CmdParams -> Annex [WorkTreeItem] workTreeItems = workTreeItems' (AllowHidden False) workTreeItems' :: AllowHidden -> CmdParams -> Annex [WorkTreeItem] workTreeItems' (AllowHidden allowhidden) ps = do currbranch <- getCurrentBranch - forM_ ps $ \p -> - unlessM (exists p <||> hidden currbranch p) $ do - toplevelWarning False (p ++ " not found") - Annex.incError + forM_ ps $ \p -> do + relf <- liftIO $ relPathCwdToFile p + ifM (not <$> (exists p <||> hidden currbranch relf)) + ( prob (p ++ " not found") + , whenM (viasymlink (upFrom relf)) $ + prob (p ++ " is beyond a symbolic link") + ) return (map (WorkTreeItem) ps) where exists p = isJust <$> liftIO (catchMaybeIO $ getSymbolicLinkStatus p) - hidden currbranch p - | allowhidden = do - f <- liftIO $ relPathCwdToFile p - isJust <$> catObjectMetaDataHidden (toRawFilePath f) currbranch + + viasymlink Nothing = return False + viasymlink (Just p) = + ifM (liftIO $ isSymbolicLink <$> getSymbolicLinkStatus p) + ( return True + , viasymlink (upFrom p) + ) + + hidden currbranch f + | allowhidden = isJust + <$> catObjectMetaDataHidden (toRawFilePath f) currbranch | otherwise = return False + prob msg = do + toplevelWarning False msg + Annex.incError + notSymlink :: RawFilePath -> IO Bool notSymlink f = liftIO $ not . isSymbolicLink <$> R.getSymbolicLinkStatus f diff --git a/Utility/Path.hs b/Utility/Path.hs index c1137d7924..b66e127142 100644 --- a/Utility/Path.hs +++ b/Utility/Path.hs @@ -88,7 +88,7 @@ parentDir :: FilePath -> FilePath parentDir = takeDirectory . dropTrailingPathSeparator {- Just the parent directory of a path, or Nothing if the path has no -- parent (ie for "/" or ".") -} +- parent (ie for "/" or "." or "foo") -} upFrom :: FilePath -> Maybe FilePath upFrom dir | length dirs < 2 = Nothing diff --git a/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn b/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn index 0ca46efe85..b7893cc569 100644 --- a/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn +++ b/doc/bugs/surprising_behavior_operating_on_file_behind_symlink.mdwn @@ -8,3 +8,5 @@ This happens because git ls-files doesn't list the file, but then I think the code that handles erroring if a file that does not exist is specified doesn't catch it because the file does exist, it's just behind the symlink. --[[Joey]] + +> [[fixed|done]] --[[Joey]]