diff --git a/src/wormhole/cli/cmd_send.py b/src/wormhole/cli/cmd_send.py index 9274de6..bbba2ce 100644 --- a/src/wormhole/cli/cmd_send.py +++ b/src/wormhole/cli/cmd_send.py @@ -254,18 +254,28 @@ class Sender: # We use realpath() instead of normpath() to locate the actual # file/directory, because the path might contain symlinks, and # normpath() would collapse those before resolving them. + # test_cli.OfferData.test_symlink_collapse tests this. - # Unfortunately on windows, realpath() is built out of normpath() - # because of a no-longer-true belief that windows does not have a - # working os.path.islink(): see https://bugs.python.org/issue9949 - # The consequence is that "wormhole send PATH" might send the wrong - # file, if: + # Unfortunately on windows, realpath() (on py3) is built out of + # normpath() because of a py2-era belief that windows lacks a working + # os.path.islink(): see https://bugs.python.org/issue9949 . The + # consequence is that "wormhole send PATH" might send the wrong file, + # if: # * we're running on windows # * PATH goes down through a symlink and then up with parent-directory # navigation (".."), then back down again # * the back-down-again portion of the path also exists under the # original directory (an error is thrown if not) + # I'd like to fix this. The core issue is sending directories with a + # trailing slash: we need to 1: open the right directory, and 2: strip + # the right parent path out of the filenames we get from os.walk(). We + # used to use what.rstrip() for this, but bug #251 reported this + # failing on windows-with-bash. realpath() works in both those cases, + # but fails with the up-down symlinks situation. I think we'll need to + # find a third way to strip the trailing slash reliably in all + # environments. + what = os.path.realpath(what) if not os.path.exists(what): raise TransferError("Cannot send: no file/directory named '%s'" % diff --git a/src/wormhole/test/test_cli.py b/src/wormhole/test/test_cli.py index 9409838..6b0265c 100644 --- a/src/wormhole/test/test_cli.py +++ b/src/wormhole/test/test_cli.py @@ -203,12 +203,6 @@ class OfferData(unittest.TestCase): def test_symlink_collapse(self): if not hasattr(os, 'symlink'): raise unittest.SkipTest("host OS does not support symlinks") - if os.name == "nt": - # ntpath.py's realpath() is built out of normpath(), and does not - # follow symlinks properly, so this test always fails. "wormhole - # send PATH" on windows will do the wrong thing. See - # https://bugs.python.org/issue9949" for details. - raise unittest.SkipTest("host OS has broken os.path.realpath(), see https://bugs.python.org/issue9949") # build A/B1, A/B1/D.txt # A/B2/C2, A/B2/D.txt # symlink A/B1/C1 -> A/B2/C2 @@ -239,6 +233,15 @@ class OfferData(unittest.TestCase): d, fd_to_send = build_offer(self.cfg) self.assertEqual(d["file"]["filename"], "D.txt") self.assertEqual(fd_to_send.read(), b"success") + if os.name == "nt": + test_symlink_collapse.todo = "host OS has broken os.path.realpath()" + # ntpath.py's realpath() is built out of normpath(), and does not + # follow symlinks properly, so this test always fails. "wormhole send + # PATH" on windows will do the wrong thing. See + # https://bugs.python.org/issue9949" for details. I'm making this a + # TODO instead of a SKIP because 1: this causes an observable + # misbehavior (albeit in rare circumstances), 2: it probably used to + # work (sometimes, but not in #251). See cmd_send.py for more notes. class LocaleFinder: def __init__(self):