(tmpdir_factory)
| 231 | @pytest.mark.skipif(os.name == "nt", reason="host OS has broken os.path.realpath()") |
| 232 | @pytest.mark.skipif(not hasattr(os, 'symlink'), reason="host OS does not support symlinks") |
| 233 | def test_symlink_collapse(tmpdir_factory): |
| 234 | cfg = create_config() |
| 235 | # build A/B1, A/B1/D.txt |
| 236 | # A/B2/C2, A/B2/D.txt |
| 237 | # symlink A/B1/C1 -> A/B2/C2 |
| 238 | parent_dir = tmpdir_factory.mktemp("parent") |
| 239 | os.mkdir(os.path.join(parent_dir, "B1")) |
| 240 | with open(os.path.join(parent_dir, "B1", "D.txt"), "wb") as f: |
| 241 | f.write(b"fail") |
| 242 | os.mkdir(os.path.join(parent_dir, "B2")) |
| 243 | os.mkdir(os.path.join(parent_dir, "B2", "C2")) |
| 244 | with open(os.path.join(parent_dir, "B2", "D.txt"), "wb") as f: |
| 245 | f.write(b"success") |
| 246 | os.symlink( |
| 247 | os.path.abspath(os.path.join(parent_dir, "B2", "C2")), |
| 248 | os.path.join(parent_dir, "B1", "C1")) |
| 249 | # Now send "B1/C1/../D.txt" from A. The correct traversal will be: |
| 250 | # * start: A |
| 251 | # * B1: A/B1 |
| 252 | # * C1: follow symlink to A/B2/C2 |
| 253 | # * ..: climb to A/B2 |
| 254 | # * D.txt: open A/B2/D.txt, which contains "success" |
| 255 | # If the code mistakenly uses normpath(), it would do: |
| 256 | # * normpath turns B1/C1/../D.txt into B1/D.txt |
| 257 | # * start: A |
| 258 | # * B1: A/B1 |
| 259 | # * D.txt: open A/B1/D.txt , which contains "fail" |
| 260 | cfg.cwd = parent_dir |
| 261 | cfg.what = os.path.join("B1", "C1", os.pardir, "D.txt") |
| 262 | d, fd_to_send = build_offer(cfg) |
| 263 | assert d["file"]["filename"] == "D.txt" |
| 264 | assert fd_to_send.read() == b"success" |
| 265 | |
| 266 | |
| 267 | async def _find_utf8_locale(): |
nothing calls this directly
no test coverage detected