使用 python zipfile 归档符号链接

archiving symlinks with python zipfile

我有一个脚本可以创建包含符号链接的目录的 zip 文件。我 惊讶地发现 zipfiles 已经压缩了目标 链接而不是链接本身,这是我想要的 预期的。有人知道如何获取 zipfile 来压缩链接吗?

zipfile doesn't appear to support storing symbolic links. The way to store them in a ZIP is actually not part of the format and is only available as a custom extension in some implementations. In particular, Info-ZIP's implementation supports them so you can delegate to it instead。确保你的解压软件可以处理这样的档案——正如我所说,这个功能没有标准化。

可以让 zipfile 存储符号 link,而不是文件本身。有关示例,请参阅 here。脚本的相关部分将符号 link 属性存储在 zipinfo:

zipInfo = zipfile.ZipInfo(archiveRoot)
zipInfo.create_system = 3
# long type of hex val of '0xA1ED0000L',
# say, symlink attr magic...
zipInfo.external_attr = 2716663808L
zipOut.writestr(zipInfo, os.readlink(fullPath))

我在 Zip 支持中定义了以下方法class

def add_symlink(self, link, target, permissions=0o777):
    self.log('Adding a symlink: {} => {}'.format(link, target))
    permissions |= 0xA000

    zi = zipfile.ZipInfo(link)
    zi.create_system = 3
    zi.external_attr = permissions << 16
    self.zip.writestr(zi, target)

请找到一个完整的 Python 代码作为工作示例,它创建一个 cpuinfo.zip 存档,其中符号 link cpuinfo.txt 指向 /proc/cpuinfo

#!/usr/bin/python

import stat
import zipfile

def create_zip_with_symlink(output_zip_filename, link_source, link_target):
    zipInfo  = zipfile.ZipInfo(link_source)
    zipInfo.create_system = 3 # System which created ZIP archive, 3 = Unix; 0 = Windows
    unix_st_mode = stat.S_IFLNK | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH
    zipInfo.external_attr = unix_st_mode << 16 # The Python zipfile module accepts the 16-bit "Mode" field (that stores st_mode field from struct stat, containing user/group/other permissions, setuid/setgid and symlink info, etc) of the ASi extra block for Unix as bits 16-31 of the external_attr
    zipOut = zipfile.ZipFile(output_zip_filename, 'w', compression=zipfile.ZIP_DEFLATED)
    zipOut.writestr(zipInfo, link_target)
    zipOut.close()

create_zip_with_symlink('cpuinfo.zip', 'cpuinfo.txt', '/proc/cpuinfo')

您可以进一步发出以下命令(例如在 Ubuntu 下)以查看存档如何解压缩为工作符号 link:

unzip cpuinfo.zip
ls -l cpuinfo.txt
cat cpuinfo.txt

虽然不是 POSIX 标准的一部分,但许多 zip 实现支持在条目上存储通用文件系统属性。 4字节值的高字节代表文件模式。

基本上您需要复制 ZipInfo.from_file,但不遵循 link 或截断模式:

st = os.lstat(path)
mtime = time.localtime(st.st_mtime)
info = zipfile.ZipInfo(name, mtime[0:6])
info.file_size = st.st_size
info.external_attr = st.st_mode << 16
out_zip.writestr(info, os.readlink(path))