Created
September 23, 2025 21:13
-
-
Save pmolodo/2938dfe7f4a76dc2d43cdc9496b720a4 to your computer and use it in GitHub Desktop.
BetterZipFile - python ZipFile subclass that handles symbolic links and permission bits when extracting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # better_zipfile by Paul Molodowitch is marked CC0 1.0. | |
| # to view a copy of this mark, visit https://creativecommons.org/publicdomain/zero/1.0/ | |
| import sys | |
| import zipfile | |
| import stat | |
| import os | |
| if sys.platform == "win32": | |
| BetterZipFile = zipfile.ZipFile | |
| else: | |
| class BetterZipFile(zipfile.ZipFile): | |
| """ | |
| ZipFile subclass that handles symbolic links and permission bits when extracting | |
| """ | |
| def _extract_member(self, member, targetpath, pwd): | |
| if not isinstance(member, zipfile.ZipInfo): | |
| member = self.getinfo(member) | |
| # Check if this is a symbolic link | |
| permission_bits = member.external_attr >> 16 | |
| if permission_bits != 0 and stat.S_ISLNK(permission_bits): | |
| # Handle symbolic links | |
| link_target = self.read(member).decode("utf-8") | |
| symlink_path = os.path.join(targetpath, member.filename) | |
| # Ensure parent directory exists | |
| os.makedirs(os.path.dirname(symlink_path), exist_ok=True) | |
| # Remove existing file/link if it exists | |
| if os.path.lexists(symlink_path): | |
| try: | |
| os.unlink(symlink_path) | |
| except Exception: | |
| print( | |
| f"Failed to remove existing file/link: {member.filename} at" | |
| f" {symlink_path}" | |
| ) | |
| raise | |
| # Create the symbolic link | |
| os.symlink(link_target, symlink_path) | |
| return targetpath | |
| # Handle regular files and directories | |
| targetpath = super()._extract_member(member, targetpath, pwd) | |
| if permission_bits != 0: | |
| os.chmod(targetpath, permission_bits) | |
| return targetpath |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment