Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python zipfile从二进制文件中删除执行权限_Python_Python 2.7 - Fatal编程技术网

Python zipfile从二进制文件中删除执行权限

Python zipfile从二进制文件中删除执行权限,python,python-2.7,Python,Python 2.7,不知道为什么会发生这种情况,但当我在命令行运行解压文件(例如apache-groovy-binary-2.4.7.zip)时 目录为rwx-r-xr-x 文件为rwxr-xr-x或rw-r--r-- 但是当我在同一个文件上从Python 2.7脚本运行zipfile.extractall()时 目录为rwx-r-x--- 所有文件都是rw-r---——甚至是上面提到的应该是可执行文件的文件 我的umask设置为0027-这部分解释了发生的情况,但为什么要从所有文件中删除可执行位 要使Py

不知道为什么会发生这种情况,但当我在命令行运行解压文件(例如apache-groovy-binary-2.4.7.zip)时

  • 目录为
    rwx-r-xr-x
  • 文件为
    rwxr-xr-x
    rw-r--r--
但是当我在同一个文件上从Python 2.7脚本运行
zipfile.extractall()

  • 目录为
    rwx-r-x---
  • 所有文件都是
    rw-r---
    ——甚至是上面提到的应该是可执行文件的文件
我的
umask
设置为
0027
-这部分解释了发生的情况,但为什么要从所有文件中删除可执行位


要使Python采用与命令行版本类似的行为(当然除了脱壳!),最简单的修复方法是什么?

原因可以在
zipfile.py
中的
\u extract\u member()
方法中找到,它只调用
shutil.copyfileobj()
它将写入输出文件,而不包含任何执行位

解决此问题的最简单方法是对
ZipFile
进行子类化并更改
extract()
(或在扩展版本中进行修补。默认情况下:

def extract(self, member, path=None, pwd=None):
    """Extract a member from the archive to the current working directory,
       using its full name. Its file information is extracted as accurately
       as possible. `member' may be a filename or a ZipInfo object. You can
       specify a different directory using `path'.
    """
    if not isinstance(member, ZipInfo):
        member = self.getinfo(member)

    if path is None:
        path = os.getcwd()

    return self._extract_member(member, path, pwd)
最后一行应更改为基于原始属性实际设置模式。您可以通过以下方式进行设置:

import os
from zipfile import ZipFile, ZipInfo

class MyZipFile(ZipFile):

    def extract(self, member, path=None, pwd=None):
        if not isinstance(member, ZipInfo):
            member = self.getinfo(member)

        if path is None:
            path = os.getcwd()

        ret_val = self._extract_member(member, path, pwd)
        attr = member.external_attr >> 16
        os.chmod(ret_val, attr)
        return ret_val


with MyZipFile('test.zip') as zfp:
    zfp.extractall()

(以上内容基于Python3.5,并假设zipfile名为
test.zip

正如Rafael Almeida所指出的,extractall在python 3.6上不起作用。一个简单的解决方法是重写extractall方法,以便它调用extract而不是_extract_member。不干净,但在ZipFile有更全面的解决方案之前一直工作

class MyZipFile(ZipFile):

    def extract(self, member, path=None, pwd=None):
        if not isinstance(member, ZipInfo):
            member = self.getinfo(member)

        if path is None:
            path = os.getcwd()

        ret_val = self._extract_member(member, path, pwd)
        attr = member.external_attr >> 16
        if attr != 0:
            os.chmod(ret_val, attr)
        return ret_val

    def extractall(self, path=None, members=None, pwd=None):
        if members is None:
            members = self.namelist()

        if path is None:
            path = os.getcwd()
        else:
            path = os.fspath(path)

        for zipinfo in members:
            self.extract(zipinfo, path, pwd)

这适用于python 3.6:

from zipfile import ZipFile, ZipInfo


class ZipFileWithPermissions(ZipFile):
""" Custom ZipFile class handling file permissions. """
    def _extract_member(self, member, targetpath, pwd):
        if not isinstance(member, ZipInfo):
            member = self.getinfo(member)

        targetpath = super()._extract_member(member, targetpath, pwd)

        attr = member.external_attr >> 16
        if attr != 0:
            os.chmod(targetpath, attr)
        return targetpath

不确定Python的实现是否支持Zip的文件集属性处理,但您应该朝这个方向看。它的工作原理如下:哦!这很好:在python2.7上测试。谢谢!@RCross,我建议您点击“答案”选中此项。根据中描述此问题的注释,在调用chmod()之前,我添加了一个检查
attr
是否为非零。这在python 3.6中不再有效,因为它调用了_extract_member而不是extract