[elbe-devel] [PATCH] filesystem: make Filesyste.realpath() handle absolute paths in links

Olivier Dion dion at linutronix.de
Mon Jun 17 18:43:45 CEST 2019


I've wrote a dozen of cases .. It cover them all .. I hope it does for
you too.  Commit is pushed on devel/dion/issue-199


Signed-off-by: Olivier Dion <dion at linutronix.de>
---
 elbepack/filesystem.py | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/elbepack/filesystem.py b/elbepack/filesystem.py
index 4c925d1c..450f1524 100644
--- a/elbepack/filesystem.py
+++ b/elbepack/filesystem.py
@@ -85,26 +85,50 @@ class Filesystem(object):
         os.makedirs(self.fname(path))
 
     def realpath(self, path):
-        if path[0] != os.sep:
-            path = os.sep + path
+
         path = path.split(os.sep)
         path.reverse()
+        following = []
         real_path = [self.path]
+
         while path:
             candidate = path.pop()
+
+            # Don't care
             if candidate == '' or candidate == os.curdir:
                 continue
-            elif candidate == os.pardir:
+
+            # Can't go out of RFS
+            if candidate == os.pardir:
+                if following:
+                    following.pop()
                 if len(real_path) > 1:
                     real_path.pop()
-            else:
+                continue
+
+            parent = os.sep.join(real_path)
+            new_path = os.path.join(parent, candidate)
+            if not os.path.islink(new_path):
+                if following:
+                    following.pop()
                 real_path.append(candidate)
-                new_path = os.sep.join(real_path)
-                if os.path.islink(new_path):
-                    elements = os.readlink(new_path)
-                    for element in reversed(elements.split(os.sep)):
-                        path.append(element)
-                    real_path.pop()
+                continue
+
+            # Circular loop; Don't follow it
+            if new_path in following:
+                real_path.append(candidate)
+                continue
+
+            following.append(new_path)
+            link = os.readlink(new_path)
+
+            # Reset root for absolute link
+            if os.path.isabs(link):
+                real_path = [self.path]
+
+            for element in reversed(link.split(os.sep)):
+                path.append(element)
+
         return os.sep.join(real_path)
 
     def symlink(self, src, path, allow_exists=False):
-- 
2.11.0Signed-off-by: Olivier Dion <dion at linutronix.de>
---
 elbepack/filesystem.py | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/elbepack/filesystem.py b/elbepack/filesystem.py
index 4c925d1c..450f1524 100644
--- a/elbepack/filesystem.py
+++ b/elbepack/filesystem.py
@@ -85,26 +85,50 @@ class Filesystem(object):
         os.makedirs(self.fname(path))
 
     def realpath(self, path):
-        if path[0] != os.sep:
-            path = os.sep + path
+
         path = path.split(os.sep)
         path.reverse()
+        following = []
         real_path = [self.path]
+
         while path:
             candidate = path.pop()
+
+            # Don't care
             if candidate == '' or candidate == os.curdir:
                 continue
-            elif candidate == os.pardir:
+
+            # Can't go out of RFS
+            if candidate == os.pardir:
+                if following:
+                    following.pop()
                 if len(real_path) > 1:
                     real_path.pop()
-            else:
+                continue
+
+            parent = os.sep.join(real_path)
+            new_path = os.path.join(parent, candidate)
+            if not os.path.islink(new_path):
+                if following:
+                    following.pop()
                 real_path.append(candidate)
-                new_path = os.sep.join(real_path)
-                if os.path.islink(new_path):
-                    elements = os.readlink(new_path)
-                    for element in reversed(elements.split(os.sep)):
-                        path.append(element)
-                    real_path.pop()
+                continue
+
+            # Circular loop; Don't follow it
+            if new_path in following:
+                real_path.append(candidate)
+                continue
+
+            following.append(new_path)
+            link = os.readlink(new_path)
+
+            # Reset root for absolute link
+            if os.path.isabs(link):
+                real_path = [self.path]
+
+            for element in reversed(link.split(os.sep)):
+                path.append(element)
+
         return os.sep.join(real_path)
 
     def symlink(self, src, path, allow_exists=False):
-- 
2.11.0

On 2019-06-14T17:29:35+0200, Torben Hohn wrote:

> the realpath() implementation is still not correct.
> but i like the approach.

> please finish it. and fold my patch into it.



> On Fri, Jun 14, 2019 at 05:28:04PM +0200, Torben Hohn wrote:
> > the current implementation fails for absolute links:
> > 
> > >>> from elbepack import filesystem
> > >>> f = filesystem.Filesystem('xxx')
> > >>> f.mkdir_p('/usr/bin')
> > >>> f.symlink('/usr/bin/vim', '/usr/bin/omg')
> > >>> f.realpath('/usr/bin/omg')
> > '/home/torbenh/elbe/elbe/xxx/usr/bin/usr/bin/vim'
> > >>>
> > 
> > handle it by "initialising" path again, when an absolute path
> > is returned from os.readlink()
> > 
> > this still lacks catching recursive links, and i think, that .. is
> > not evaluated properly in any case.
> > 
> > Signed-off-by: Torben Hohn <torben.hohn at linutronix.de>
> > ---
> >  elbepack/filesystem.py | 11 ++++++++---
> >  1 file changed, 8 insertions(+), 3 deletions(-)
> > 
> > diff --git a/elbepack/filesystem.py b/elbepack/filesystem.py
> > index 4c925d1c6..91dbe0879 100644
> > --- a/elbepack/filesystem.py
> > +++ b/elbepack/filesystem.py
> > @@ -102,9 +102,14 @@ class Filesystem(object):
> >                  new_path = os.sep.join(real_path)
> >                  if os.path.islink(new_path):
> >                      elements = os.readlink(new_path)
> > -                    for element in reversed(elements.split(os.sep)):
> > -                        path.append(element)
> > -                    real_path.pop()
> > +                    if os.path.isabs(elements):
> > +                        path = elements.split(os.sep)
> > +                        path.reverse()
> > +                        real_path = [self.path]
> > +                    else:
> > +                        for element in reversed(elements.split(os.sep)):
> > +                            path.append(element)
> > +                        real_path.pop()
> >          return os.sep.join(real_path)
> >  
> >      def symlink(self, src, path, allow_exists=False):
> > -- 
> > 2.11.0
> > 
> > 
> > _______________________________________________
> > elbe-devel mailing list
> > elbe-devel at linutronix.de
> > https://lists.linutronix.de/mailman/listinfo/elbe-devel

> -- 
> Torben Hohn
> Linutronix GmbH | Bahnhofstrasse 3 | D-88690 Uhldingen-Mühlhofen
> Phone: +49 7556 25 999 18; Fax.: +49 7556 25 999 99

> Hinweise zum Datenschutz finden Sie hier (Informations on data privacy 
> can be found here): https://linutronix.de/kontakt/Datenschutz.php

> Linutronix GmbH | Firmensitz (Registered Office): Uhldingen-Mühlhofen | 
> Registergericht (Registration Court): Amtsgericht Freiburg i.Br., HRB700 
> 806 | Geschäftsführer (Managing Directors): Heinz Egger, Thomas Gleixner


-- 
Olivier Dion
Linutronix GmbH | Bahnhofstrasse 3 | D-88690 Uhldingen-Mühlhofen



More information about the elbe-devel mailing list