Skip to content

Commit db7f204

Browse files
committed
rsync: use a more robust check for relative link than "startswith"
`startswith` is incorrect for paths in general, e.g. doesn't handle Windows extended-length paths and other such. The particular code here also wasn't careful about `/a/bc` not being relative to `/a/b`.
1 parent 8f0e8ec commit db7f204

File tree

1 file changed

+19
-3
lines changed

1 file changed

+19
-3
lines changed

execnet/rsync.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,26 @@ def _send_directory(self, path):
173173
self._send_directory_structure(p)
174174

175175
def _send_link_structure(self, path):
176-
linkpoint = os.readlink(path)
176+
sourcedir = self._sourcedir
177177
basename = path[len(self._sourcedir) + 1 :]
178-
if linkpoint.startswith(self._sourcedir):
179-
self._send_link("linkbase", basename, linkpoint[len(self._sourcedir) + 1 :])
178+
linkpoint = os.readlink(path)
179+
# On Windows, readlink returns an extended path (//?/) for
180+
# absolute links, but relpath doesn't like mixing extended
181+
# and non-extended paths. So fix it up ourselves.
182+
if (
183+
os.path.__name__ == "ntpath"
184+
and linkpoint.startswith("\\\\?\\")
185+
and not self._sourcedir.startswith("\\\\?\\")
186+
):
187+
sourcedir = "\\\\?\\" + self._sourcedir
188+
try:
189+
relpath = os.path.relpath(linkpoint, sourcedir)
190+
except ValueError:
191+
relpath = None
192+
if relpath not in (None, os.curdir, os.pardir) and not relpath.startswith(
193+
os.pardir + os.sep
194+
):
195+
self._send_link("linkbase", basename, relpath)
180196
else:
181197
# relative or absolute link, just send it
182198
self._send_link("link", basename, linkpoint)

0 commit comments

Comments
 (0)