diff mbox series

[bitbake-devel,1/2] utils: Add path_is_descendant()

Message ID 20230913190425.3761792-2-JPEWhacker@gmail.com
State New
Headers show
Series fetch2: git: Fix path check for git repos | expand

Commit Message

Joshua Watt Sept. 13, 2023, 7:04 p.m. UTC
Adds a utility that checks if one path is an descendant of another. This
check uses os.path.samestat() to make it immune to symlinks and bind

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
 bitbake/lib/bb/utils.py | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
diff mbox series


diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py
index 0624a4f3e9a..b401fa5ec7a 100644
--- a/bitbake/lib/bb/utils.py
+++ b/bitbake/lib/bb/utils.py
@@ -1828,6 +1828,29 @@  def mkstemp(suffix=None, prefix=None, dir=None, text=False):
         prefix = tempfile.gettempprefix() + entropy
     return tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir, text=text)
+def path_is_descendant(descendant, ancestor):
+    """
+    Returns True if the path `descendant` is a descendant of `ancestor`
+    (including being equivalent to `ancestor` itself). Otherwise returns False.
+    Correctly accounts for symlinks, bind mounts, etc. by using
+    os.path.samestat() to compare paths
+    May raise any exception that os.stat() raises
+    """
+    ancestor_stat = os.stat(ancestor)
+    # Recurse up each directory component of the descendant to see if it is
+    # equivalent to the ancestor
+    check_dir = os.path.abspath(descendant).rstrip("/")
+    while check_dir:
+        check_stat = os.stat(check_dir)
+        if os.path.samestat(check_stat, ancestor_stat):
+            return True
+        check_dir = os.path.dirname(check_dir).rstrip("/")
+    return False
 # If we don't have a timeout of some kind and a process/thread exits badly (for example
 # OOM killed) and held a lock, we'd just hang in the lock futex forever. It is better
 # we exit at some point than hang. 5 minutes with no progress means we're probably deadlocked.