Python 文件权限中的 Zipfile
Zipfile in Python file permission
我使用 zipfile
lib 从 zip 中提取文件,现在在解压缩目录后我发现我的文件的权限已损坏,
import zipfile
fh = open('sample.zip', 'rb')
z = zipfile.ZipFile(fh)
print z.namelist()
for name in z.namelist():
z.extract(name, '/tmp/')
fh.close()
但是当我使用 linux
解压缩工具时,这个问题不会发生
我尝试使用
os.system('unzip sample.zip')
但我还是想用 zipfile
import zipfile
import os
unZipFile = zipfile.ZipFile("sample.zip", "r")
tmp_dir = "/tmp"
try:
for info in unZipFile.infolist():
real_path = unZipFile.extract(info, tmp_dir)
# permission
unix_attributes = info.external_attr >> 16
target = os.path.join(tmp_dir, info.filename)
if unix_attributes:
os.chmod(target, unix_attributes)
if not real_path:
print "Extract failed: " + info.filename
finally:
unZipFile.close()
相关的 Python 问题提供了一些关于问题最初存在原因的见解:https://bugs.python.org/issue18262 and https://bugs.python.org/issue15795
此外,原始 Zip 规范可在此处找到:https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
重要的部分是:
4.4.2 version made by (2 bytes)
4.4.2.1 The upper byte indicates the compatibility of the file
attribute information. If the external file attributes
are compatible with MS-DOS and can be read by PKZIP for
DOS version 2.04g then this value will be zero. If these
attributes are not compatible, then this value will
identify the host system on which the attributes are
compatible. Software can use this information to determine
the line record format for text files etc.
4.4.2.2 The current mappings are:
0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)
1 - Amiga 2 - OpenVMS
3 - UNIX 4 - VM/CMS
5 - Atari ST 6 - OS/2 H.P.F.S.
7 - Macintosh 8 - Z-System
9 - CP/M 10 - Windows NTFS
11 - MVS (OS/390 - Z/OS) 12 - VSE
13 - Acorn Risc 14 - VFAT
15 - alternate MVS 16 - BeOS
17 - Tandem 18 - OS/400
19 - OS X (Darwin) 20 thru 255 - unused
...
4.4.15 external file attributes: (4 bytes)
The mapping of the external attributes is
host-system dependent (see 'version made by'). For
MS-DOS, the low order byte is the MS-DOS directory
attribute byte. If input came from standard input, this
field is set to zero.
这意味着外部文件属性是系统特定的。解释不同系统的外部文件属性可能会使情况变得更糟。如果我们只关心 UNIX,我们可以检查 ZipInfo.created_system
并将其与 3
(对于 UNIX)进行比较。不幸的是,该规范在如何解释外部属性方面没有进一步帮助我们。
这个 Wiki 里有东西 http://forensicswiki.org/wiki/Zip#External_file_attributes
The external attributes UNIX (3) is 4 bytes of size and consists of:
╔═════════╦══════════╦════════╦═══════════════════════════════════════════════════════╗
║ Offset ║ Size ║ Value ║ Description ║
╠═════════╬══════════╬════════╬═══════════════════════════════════════════════════════╣
║ 0 ║ 1 ║ ║ FAT (MS-DOS) file attributes. ║
║ 1 ║ 1 ║ ║ Unknown ║
║ 2 ║ 16 bits ║ ║ The UNIX mode (or permission). ║
║ ║ ║ ║ The value seems to be similar to stat.st_mode value. ║
╚═════════╩══════════╩════════╩═══════════════════════════════════════════════════════╝
虽然这是相当观察性的,但这似乎是共识。
综合起来:
from zipfile import ZipFile
ZIP_UNIX_SYSTEM = 3
def extract_all_with_permission(zf, target_dir):
for info in zf.infolist():
extracted_path = zf.extract(info, target_dir)
if info.create_system == ZIP_UNIX_SYSTEM:
unix_attributes = info.external_attr >> 16
if unix_attributes:
os.chmod(extracted_path, unix_attributes)
with ZipFile('sample.zip', 'r') as zf:
extract_all_with_permission(zf, '/tmp')
可能会有一个问题,为什么我们首先要保留权限。可能有人敢说我们只想保留可执行标志。在这种情况下,一个稍微安全一点的选择可能是只恢复可执行标志,仅针对文件。
from zipfile import ZipFile
from stat import S_IXUSR
ZIP_UNIX_SYSTEM = 3
def extract_all_with_executable_permission(zf, target_dir):
for info in zf.infolist():
extracted_path = zf.extract(info, target_dir)
if info.create_system == ZIP_UNIX_SYSTEM and os.path.isfile(extracted_path):
unix_attributes = info.external_attr >> 16
if unix_attributes & S_IXUSR:
os.chmod(extracted_path, os.stat(extracted_path).st_mode | S_IXUSR)
with ZipFile('sample.zip', 'r') as zf:
extract_all_with_executable_permission(zf, '/tmp')
我使用 zipfile
lib 从 zip 中提取文件,现在在解压缩目录后我发现我的文件的权限已损坏,
import zipfile
fh = open('sample.zip', 'rb')
z = zipfile.ZipFile(fh)
print z.namelist()
for name in z.namelist():
z.extract(name, '/tmp/')
fh.close()
但是当我使用 linux
解压缩工具时,这个问题不会发生
我尝试使用
os.system('unzip sample.zip')
但我还是想用 zipfile
import zipfile
import os
unZipFile = zipfile.ZipFile("sample.zip", "r")
tmp_dir = "/tmp"
try:
for info in unZipFile.infolist():
real_path = unZipFile.extract(info, tmp_dir)
# permission
unix_attributes = info.external_attr >> 16
target = os.path.join(tmp_dir, info.filename)
if unix_attributes:
os.chmod(target, unix_attributes)
if not real_path:
print "Extract failed: " + info.filename
finally:
unZipFile.close()
相关的 Python 问题提供了一些关于问题最初存在原因的见解:https://bugs.python.org/issue18262 and https://bugs.python.org/issue15795
此外,原始 Zip 规范可在此处找到:https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
重要的部分是:
4.4.2 version made by (2 bytes) 4.4.2.1 The upper byte indicates the compatibility of the file attribute information. If the external file attributes are compatible with MS-DOS and can be read by PKZIP for DOS version 2.04g then this value will be zero. If these attributes are not compatible, then this value will identify the host system on which the attributes are compatible. Software can use this information to determine the line record format for text files etc. 4.4.2.2 The current mappings are: 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems) 1 - Amiga 2 - OpenVMS 3 - UNIX 4 - VM/CMS 5 - Atari ST 6 - OS/2 H.P.F.S. 7 - Macintosh 8 - Z-System 9 - CP/M 10 - Windows NTFS 11 - MVS (OS/390 - Z/OS) 12 - VSE 13 - Acorn Risc 14 - VFAT 15 - alternate MVS 16 - BeOS 17 - Tandem 18 - OS/400 19 - OS X (Darwin) 20 thru 255 - unused ... 4.4.15 external file attributes: (4 bytes) The mapping of the external attributes is host-system dependent (see 'version made by'). For MS-DOS, the low order byte is the MS-DOS directory attribute byte. If input came from standard input, this field is set to zero.
这意味着外部文件属性是系统特定的。解释不同系统的外部文件属性可能会使情况变得更糟。如果我们只关心 UNIX,我们可以检查 ZipInfo.created_system
并将其与 3
(对于 UNIX)进行比较。不幸的是,该规范在如何解释外部属性方面没有进一步帮助我们。
这个 Wiki 里有东西 http://forensicswiki.org/wiki/Zip#External_file_attributes
The external attributes UNIX (3) is 4 bytes of size and consists of: ╔═════════╦══════════╦════════╦═══════════════════════════════════════════════════════╗ ║ Offset ║ Size ║ Value ║ Description ║ ╠═════════╬══════════╬════════╬═══════════════════════════════════════════════════════╣ ║ 0 ║ 1 ║ ║ FAT (MS-DOS) file attributes. ║ ║ 1 ║ 1 ║ ║ Unknown ║ ║ 2 ║ 16 bits ║ ║ The UNIX mode (or permission). ║ ║ ║ ║ ║ The value seems to be similar to stat.st_mode value. ║ ╚═════════╩══════════╩════════╩═══════════════════════════════════════════════════════╝
虽然这是相当观察性的,但这似乎是共识。
综合起来:
from zipfile import ZipFile
ZIP_UNIX_SYSTEM = 3
def extract_all_with_permission(zf, target_dir):
for info in zf.infolist():
extracted_path = zf.extract(info, target_dir)
if info.create_system == ZIP_UNIX_SYSTEM:
unix_attributes = info.external_attr >> 16
if unix_attributes:
os.chmod(extracted_path, unix_attributes)
with ZipFile('sample.zip', 'r') as zf:
extract_all_with_permission(zf, '/tmp')
可能会有一个问题,为什么我们首先要保留权限。可能有人敢说我们只想保留可执行标志。在这种情况下,一个稍微安全一点的选择可能是只恢复可执行标志,仅针对文件。
from zipfile import ZipFile
from stat import S_IXUSR
ZIP_UNIX_SYSTEM = 3
def extract_all_with_executable_permission(zf, target_dir):
for info in zf.infolist():
extracted_path = zf.extract(info, target_dir)
if info.create_system == ZIP_UNIX_SYSTEM and os.path.isfile(extracted_path):
unix_attributes = info.external_attr >> 16
if unix_attributes & S_IXUSR:
os.chmod(extracted_path, os.stat(extracted_path).st_mode | S_IXUSR)
with ZipFile('sample.zip', 'r') as zf:
extract_all_with_executable_permission(zf, '/tmp')