Fix using lookupkey inside a subdirectory
authorJoey Hess <joeyh@joeyh.name>
Tue, 26 Oct 2021 18:58:44 +0000 (14:58 -0400)
committerJoey Hess <joeyh@joeyh.name>
Tue, 26 Oct 2021 19:00:45 +0000 (15:00 -0400)
Caused by dirContains ".." "foo" being incorrectly False.

Also added a test of dirContains, which includes all the previous bug fixes
I could find and some obvious cases.

Reversion in version 8.20211011

Sponsored-by: Brett Eisenberg on Patreon
CHANGELOG
Test.hs
Utility/Path.hs
Utility/Path/Tests.hs
doc/bugs/lookupkey_does_not_work_from_subdirectory.mdwn

index 5b3566f7f5ea4a2834d0fa67f5a4d729cd4e6b01..a4d728f3e442463f793e3b7f58323e4d5bd116c5 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,6 +20,8 @@ git-annex (8.20211012) UNRELEASED; urgency=medium
   * Avoid a some sqlite crashes on Windows SubSystem for Linux (WSL).
   * Fix bug that caused stale git-annex branch information to read
     when annex.private or remote.name.annex-private is set.
+  * Fix using lookupkey inside a subdirectory.
+    (Reversion in version 8.20211011)
 
  -- Joey Hess <id@joeyh.name>  Mon, 11 Oct 2021 14:09:13 -0400
 
diff --git a/Test.hs b/Test.hs
index d0647c37f1f3737fd7f50aa143a276ac0b20dbaf..3d0f02ef89b9f2285f8a0c486003c2934e8b6632 100644 (file)
--- a/Test.hs
+++ b/Test.hs
@@ -194,6 +194,7 @@ properties = localOption (QuickCheckTests 1000) $ testGroup "QuickCheck" $
        , testProperty "prop_upFrom_basics" Utility.Path.Tests.prop_upFrom_basics
        , testProperty "prop_relPathDirToFileAbs_basics" Utility.Path.Tests.prop_relPathDirToFileAbs_basics
        , testProperty "prop_relPathDirToFileAbs_regressionTest" Utility.Path.Tests.prop_relPathDirToFileAbs_regressionTest
+       , testProperty "prop_dirContains_regressionTest" Utility.Path.Tests.prop_dirContains_regressionTest
        , testProperty "prop_cost_sane" Config.Cost.prop_cost_sane
        , testProperty "prop_matcher_sane" Utility.Matcher.prop_matcher_sane
        , testProperty "prop_HmacSha1WithCipher_sane" Crypto.prop_HmacSha1WithCipher_sane
index 4a47367d78212ce0cb023a85b4ddf5341ed77b2e..b5aeb16fd00fcecd1dcb0cda53aac7bd4afc817c 100644 (file)
@@ -97,6 +97,7 @@ dirContains a b = a == b
        || a' == b'
        || (a'' `B.isPrefixOf` b' && avoiddotdotb)
        || a' == "." && normalise ("." </> b') == b' && nodotdot b'
+       || dotdotcontains
   where
        a' = norm a
        a'' = addTrailingPathSeparator a'
@@ -115,9 +116,27 @@ dirContains a b = a == b
         -}
        avoiddotdotb = nodotdot $ B.drop (B.length a'') b'
 
-       nodotdot p = all
-               (\s -> dropTrailingPathSeparator s /= "..")
-               (splitPath p)
+       nodotdot p = all (not . isdotdot) (splitPath p)
+       
+       isdotdot s = dropTrailingPathSeparator s == ".."
+
+       {- This handles the case where a is ".." or "../.." etc,
+        - and b is "foo" or "../foo" etc. The rule is that when
+        - a is entirely ".." components, b is under it when it starts
+        - with fewer ".." components. 
+        - 
+        - Due to the use of norm, cases like "../../foo/../../" get
+        - converted to eg "../../../" and so do not need to be handled
+        - specially here.
+        -}
+       dotdotcontains
+               | isAbsolute b' = False
+               | otherwise = 
+                       let aps = splitPath a'
+                           bps = splitPath b'
+                       in if all isdotdot aps
+                               then length (takeWhile isdotdot bps) < length aps
+                               else False
 
 {- Given an original list of paths, and an expanded list derived from it,
  - which may be arbitrarily reordered, generates a list of lists, where
index 94deff936764f4ff6905392ece8893a9260e6208..b35e8867d682e17cf3b220254e5cdd6d6f155f45 100644 (file)
@@ -14,6 +14,7 @@ module Utility.Path.Tests (
        prop_upFrom_basics,
        prop_relPathDirToFileAbs_basics,
        prop_relPathDirToFileAbs_regressionTest,
+       prop_dirContains_regressionTest,
 ) where
 
 import System.FilePath.ByteString
@@ -62,3 +63,18 @@ prop_relPathDirToFileAbs_regressionTest = same_dir_shortcurcuits_at_difference
                relPathDirToFileAbs (joinPath [pathSeparator `B.cons` "tmp", "r", "lll", "xxx", "yyy", "18"])
                        (joinPath [pathSeparator `B.cons` "tmp", "r", ".git", "annex", "objects", "18", "gk", "SHA256-foo", "SHA256-foo"])
                                == joinPath ["..", "..", "..", "..", ".git", "annex", "objects", "18", "gk", "SHA256-foo", "SHA256-foo"]
+
+prop_dirContains_regressionTest :: Bool
+prop_dirContains_regressionTest = and
+       [ not $ dirContains "." ".."
+       , not $ dirContains ".." "../.."
+       , dirContains "." "foo"
+       , dirContains "." "."
+       , dirContains ".." ".."
+       , dirContains "../.." "../.."
+       , dirContains "." "./foo"
+       , dirContains ".." "../foo"
+       , dirContains "../.." "../foo"
+       , dirContains "../.." "../../foo"
+       , not $ dirContains "../.." "../../.."
+       ]
index c60f4a08b71893859a6437a18f2deca3d61659c9..bafba3ce2fdb5e46dd15376c8d3e3d76ac21bf70 100644 (file)
@@ -19,3 +19,5 @@ git-annex lookupkey latex/lshort.pdf  # Succeeds
 8.20211011 on macOS 11.6
 
 [[!meta author=jwodder]]
+
+> [[fixed|done]] --[[Joey]]