Cherry-pick cc78fa170:
Revert 22c60c18c and introduce a better detection
for symlink-loops. For example this is ok:
dir1/
dir2/
symdir -> dir2/
While this is a loop:
dir1/
symdir -> ../dir1/
... | ... |
@@ -23,16 +23,26 @@ def _fswalk_follow_symlinks(path): |
23 | 23 |
''' |
24 | 24 |
Walk filesystem, following symbolic links (but without recursion), on python2.4 and later |
25 | 25 |
|
26 |
- If a recursive directory link is detected, emit a warning and skip. |
|
26 |
+ If a symlink directory loop is detected, emit a warning and skip. |
|
27 |
+ E.g. |
|
28 |
+ dir1/ |
|
29 |
+ dir2/ |
|
30 |
+ sym-dir -> ../dir2 |
|
27 | 31 |
''' |
28 | 32 |
assert os.path.isdir(path) # only designed for directory argument |
29 |
- walkdirs = [path] |
|
33 |
+ walkdirs = set([path]) |
|
30 | 34 |
for dirpath, dirnames, filenames in os.walk(path): |
31 |
- handle_exclude_include_walk(dirpath, dirnames, []) |
|
35 |
+ handle_exclude_include_walk(dirpath, dirnames, []) |
|
36 |
+ real_dirpath = os.path.realpath(dirpath) |
|
32 | 37 |
for dirname in dirnames: |
33 | 38 |
current = os.path.join(dirpath, dirname) |
39 |
+ real_current = os.path.realpath(current) |
|
34 | 40 |
if os.path.islink(current): |
35 |
- walkdirs.append(current) |
|
41 |
+ if (real_dirpath == real_current or |
|
42 |
+ real_dirpath.startswith(real_current + os.path.sep)): |
|
43 |
+ warning("Skipping recursively symlinked directory %s" % dirname) |
|
44 |
+ else: |
|
45 |
+ walkdirs.add(current) |
|
36 | 46 |
for walkdir in walkdirs: |
37 | 47 |
for dirpath, dirnames, filenames in os.walk(walkdir): |
38 | 48 |
handle_exclude_include_walk(dirpath, dirnames, []) |