| 581 | realpath = abspath |
| 582 | else: |
| 583 | def _readlink_deep(path): |
| 584 | # These error codes indicate that we should stop reading links and |
| 585 | # return the path we currently have. |
| 586 | # 1: ERROR_INVALID_FUNCTION |
| 587 | # 2: ERROR_FILE_NOT_FOUND |
| 588 | # 3: ERROR_DIRECTORY_NOT_FOUND |
| 589 | # 5: ERROR_ACCESS_DENIED |
| 590 | # 21: ERROR_NOT_READY (implies drive with no media) |
| 591 | # 32: ERROR_SHARING_VIOLATION (probably an NTFS paging file) |
| 592 | # 50: ERROR_NOT_SUPPORTED (implies no support for reparse points) |
| 593 | # 67: ERROR_BAD_NET_NAME (implies remote server unavailable) |
| 594 | # 87: ERROR_INVALID_PARAMETER |
| 595 | # 4390: ERROR_NOT_A_REPARSE_POINT |
| 596 | # 4392: ERROR_INVALID_REPARSE_DATA |
| 597 | # 4393: ERROR_REPARSE_TAG_INVALID |
| 598 | allowed_winerror = 1, 2, 3, 5, 21, 32, 50, 67, 87, 4390, 4392, 4393 |
| 599 | |
| 600 | seen = set() |
| 601 | while normcase(path) not in seen: |
| 602 | seen.add(normcase(path)) |
| 603 | try: |
| 604 | old_path = path |
| 605 | path = _nt_readlink(path) |
| 606 | # Links may be relative, so resolve them against their |
| 607 | # own location |
| 608 | if not isabs(path): |
| 609 | # If it's something other than a symlink, we don't know |
| 610 | # what it's actually going to be resolved against, so |
| 611 | # just return the old path. |
| 612 | if not islink(old_path): |
| 613 | path = old_path |
| 614 | break |
| 615 | path = normpath(join(dirname(old_path), path)) |
| 616 | except OSError as ex: |
| 617 | if ex.winerror in allowed_winerror: |
| 618 | break |
| 619 | raise |
| 620 | except ValueError: |
| 621 | # Stop on reparse points that are not symlinks |
| 622 | break |
| 623 | return path |
| 624 | |
| 625 | def _getfinalpathname_nonstrict(path): |
| 626 | # These error codes indicate that we should stop resolving the path |