如何使用Python的zipfile模块对ZIP文件中的文件设置权限(属性)?

时间:2022-12-07 18:09:33

When I extract files from a ZIP file created with the Python zipfile module, all the files are not writable, read only etc.

当我从使用Python zipfile模块创建的ZIP文件中提取文件时,所有的文件都不是可写的、只读的等等。

The file is being created and extracted under Linux and Python 2.5.2.

该文件正在Linux和Python 2.5.2中创建和提取。

As best I can tell, I need to set the ZipInfo.external_attr property for each file, but this doesn't seem to be documented anywhere I could find, can anyone enlighten me?

我可以告诉你,我需要设置ZipInfo。每个文件的external_attr属性,但这似乎并没有被记录在任何我能找到的地方,任何人都能启发我吗?

5 个解决方案

#1


33  

This seems to work (thanks Evan, putting it here so the line is in context):

这似乎起作用了(谢谢Evan,把它放在这里,所以这条线在上下文中):

buffer = "path/filename.zip"  # zip filename to write (or file-like object)
name = "folder/data.txt"      # name of file inside zip 
bytes = "blah blah blah"      # contents of file inside zip

zip = zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED)
info = zipfile.ZipInfo(name)
info.external_attr = 0777 << 16L # give full access to included file
zip.writestr(info, bytes)
zip.close()

I'd still like to see something that documents this... An additional resource I found was a note on the Zip file format: http://www.pkware.com/documents/casestudies/APPNOTE.TXT

我还想看一些文件……我找到的另一个资源是关于Zip文件格式的说明:http://www.pkware.com/documents/casestudies/APPNOTE.TXT。

#2


18  

This link has more information than anything else I've been able to find on the net. Even the zip source doesn't have anything. Copying the relevant section for posterity. This patch isn't really about documenting this format, which just goes to show how pathetic (read non-existent) the current documentation is.

这个链接比我在网上找到的任何东西都多。即使是zip源代码也没有任何东西。为后代复制相关的部分。这个补丁并不是真正的记录这种格式,它只是显示了当前文档是多么可怜(不存在)。

# external_attr is 4 bytes in size. The high order two
# bytes represent UNIX permission and file type bits,
# while the low order two contain MS-DOS FAT file
# attributes, most notably bit 4 marking directories.
if node.isfile:
    zipinfo.compress_type = ZIP_DEFLATED
    zipinfo.external_attr = 0644 << 16L # permissions -r-wr--r--
    data = node.get_content().read()
    properties = node.get_properties()
    if 'svn:special' in properties and \
           data.startswith('link '):
        data = data[5:]
        zipinfo.external_attr |= 0120000 << 16L # symlink file type
        zipinfo.compress_type = ZIP_STORED
    if 'svn:executable' in properties:
        zipinfo.external_attr |= 0755 << 16L # -rwxr-xr-x
    zipfile.writestr(zipinfo, data)
elif node.isdir and path:
    if not zipinfo.filename.endswith('/'):
        zipinfo.filename += '/'
    zipinfo.compress_type = ZIP_STORED
    zipinfo.external_attr = 040755 << 16L # permissions drwxr-xr-x
    zipinfo.external_attr |= 0x10 # MS-DOS directory flag
    zipfile.writestr(zipinfo, '')

Also, this link has the following. Here the low order byte presumably means the rightmost (lowest) byte of the four bytes. So this one is for MS-DOS and can presumably be left as zero otherwise.

另外,这个链接有以下内容。这里的低位字节可能是四个字节的最右(最低)字节。所以这个是MS-DOS,否则可能是0。

external file attributes: (4 bytes)

外部文件属性:(4字节)

      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.

Also, the source file unix/unix.c in the sources for InfoZIP's zip program, downloaded from Debian's archives has the following in comments.

还有,源文件unix/unix。从Debian的档案中下载的InfoZIP压缩程序的源代码中有以下注释。

  /* lower-middle external-attribute byte (unused until now):
   *   high bit        => (have GMT mod/acc times) >>> NO LONGER USED! <<<
   *   second-high bit => have Unix UID/GID info
   * NOTE: The high bit was NEVER used in any official Info-ZIP release,
   *       but its future use should be avoided (if possible), since it
   *       was used as "GMT mod/acc times local extra field" flags in Zip beta
   *       versions 2.0j up to 2.0v, for about 1.5 years.
   */

So taking all this together, it looks like only the second highest byte is actually used, at least for Unix.

因此,把所有这些结合起来,看起来只有第二个最高字节实际上被使用了,至少在Unix中是这样。

EDIT: I asked about the Unix aspect of this on Unix.SX, in the question "The zip format's external file attribute". Looks like I got a couple of things wrong. Specifically both of the top two bytes are used for Unix.

编辑:我在Unix上询问了Unix方面的问题。SX,在问题“zip格式的外部文件属性”。看来我弄错了。具体来说,这两个前两个字节都用于Unix。

#3


12  

Look at this: Set permissions on a compressed file in python

看看这个:在python中设置一个压缩文件的权限。

I'm not entirely sure if that's what you want, but it seems to be.

我不完全确定这是否是你想要的,但它似乎是。

The key line appears to be:

关键是:

zi.external_attr = 0777 << 16L

It looks like it sets the permissions to 0777 there.

看起来它将权限设置为0777。

#4


5  

The earlier answers did not work for me (on OS X 10.12). I found that as well as the executable flags (octal 755), I also need to set the "regular file" flag (octal 100000). I found this mentioned here: https://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute

早期的答案对我不起作用(在OS X 10.12上)。我发现,除了可执行的标志(octal 755),我还需要设置“常规文件”标志(octal 100000)。我发现这里提到的是:https://unix.stackexchange.com/questions/14705/zip -formats-external-file-attribute。

A complete example:

一个完整的例子:

zipname = "test.zip"
filename = "test-executable"

zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)

f = open(filename, 'r')
bytes = f.read()
f.close()

info = zipfile.ZipInfo(filename)
info.date_time = time.localtime()
info.external_attr = 0100755 << 16L

zip.writestr(info, bytes, zipfile.ZIP_DEFLATED)

zip.close()

A complete example of my specific usecase, creating a zip of a .app so that everything in the folder Contents/MacOS/ is executable: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

一个完整的例子,我的具体的usecase,创建一个zip的一个。应用程序,以便所有的文件夹内容/MacOS/是可执行的:https://gist.github.com/draknek/3ce889860cea4f59836a79cc11a85。

#5


0  

When you do it like this, does it work alright?

当你这样做的时候,它能正常工作吗?

zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
    f = open(name, 'wb')
    f.write(self.read(name))
    f.close()

If not, I'd suggest throwing in an os.chmod in the for loop with 0777 permissions like this:

如果没有,我建议你扔一个操作系统。chmod在for循环中有0777这样的权限:

zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
    f = open(name, 'wb')
    f.write(self.read(name))
    f.close()
    os.chmod(name, 0777)

#1


33  

This seems to work (thanks Evan, putting it here so the line is in context):

这似乎起作用了(谢谢Evan,把它放在这里,所以这条线在上下文中):

buffer = "path/filename.zip"  # zip filename to write (or file-like object)
name = "folder/data.txt"      # name of file inside zip 
bytes = "blah blah blah"      # contents of file inside zip

zip = zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED)
info = zipfile.ZipInfo(name)
info.external_attr = 0777 << 16L # give full access to included file
zip.writestr(info, bytes)
zip.close()

I'd still like to see something that documents this... An additional resource I found was a note on the Zip file format: http://www.pkware.com/documents/casestudies/APPNOTE.TXT

我还想看一些文件……我找到的另一个资源是关于Zip文件格式的说明:http://www.pkware.com/documents/casestudies/APPNOTE.TXT。

#2


18  

This link has more information than anything else I've been able to find on the net. Even the zip source doesn't have anything. Copying the relevant section for posterity. This patch isn't really about documenting this format, which just goes to show how pathetic (read non-existent) the current documentation is.

这个链接比我在网上找到的任何东西都多。即使是zip源代码也没有任何东西。为后代复制相关的部分。这个补丁并不是真正的记录这种格式,它只是显示了当前文档是多么可怜(不存在)。

# external_attr is 4 bytes in size. The high order two
# bytes represent UNIX permission and file type bits,
# while the low order two contain MS-DOS FAT file
# attributes, most notably bit 4 marking directories.
if node.isfile:
    zipinfo.compress_type = ZIP_DEFLATED
    zipinfo.external_attr = 0644 << 16L # permissions -r-wr--r--
    data = node.get_content().read()
    properties = node.get_properties()
    if 'svn:special' in properties and \
           data.startswith('link '):
        data = data[5:]
        zipinfo.external_attr |= 0120000 << 16L # symlink file type
        zipinfo.compress_type = ZIP_STORED
    if 'svn:executable' in properties:
        zipinfo.external_attr |= 0755 << 16L # -rwxr-xr-x
    zipfile.writestr(zipinfo, data)
elif node.isdir and path:
    if not zipinfo.filename.endswith('/'):
        zipinfo.filename += '/'
    zipinfo.compress_type = ZIP_STORED
    zipinfo.external_attr = 040755 << 16L # permissions drwxr-xr-x
    zipinfo.external_attr |= 0x10 # MS-DOS directory flag
    zipfile.writestr(zipinfo, '')

Also, this link has the following. Here the low order byte presumably means the rightmost (lowest) byte of the four bytes. So this one is for MS-DOS and can presumably be left as zero otherwise.

另外,这个链接有以下内容。这里的低位字节可能是四个字节的最右(最低)字节。所以这个是MS-DOS,否则可能是0。

external file attributes: (4 bytes)

外部文件属性:(4字节)

      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.

Also, the source file unix/unix.c in the sources for InfoZIP's zip program, downloaded from Debian's archives has the following in comments.

还有,源文件unix/unix。从Debian的档案中下载的InfoZIP压缩程序的源代码中有以下注释。

  /* lower-middle external-attribute byte (unused until now):
   *   high bit        => (have GMT mod/acc times) >>> NO LONGER USED! <<<
   *   second-high bit => have Unix UID/GID info
   * NOTE: The high bit was NEVER used in any official Info-ZIP release,
   *       but its future use should be avoided (if possible), since it
   *       was used as "GMT mod/acc times local extra field" flags in Zip beta
   *       versions 2.0j up to 2.0v, for about 1.5 years.
   */

So taking all this together, it looks like only the second highest byte is actually used, at least for Unix.

因此,把所有这些结合起来,看起来只有第二个最高字节实际上被使用了,至少在Unix中是这样。

EDIT: I asked about the Unix aspect of this on Unix.SX, in the question "The zip format's external file attribute". Looks like I got a couple of things wrong. Specifically both of the top two bytes are used for Unix.

编辑:我在Unix上询问了Unix方面的问题。SX,在问题“zip格式的外部文件属性”。看来我弄错了。具体来说,这两个前两个字节都用于Unix。

#3


12  

Look at this: Set permissions on a compressed file in python

看看这个:在python中设置一个压缩文件的权限。

I'm not entirely sure if that's what you want, but it seems to be.

我不完全确定这是否是你想要的,但它似乎是。

The key line appears to be:

关键是:

zi.external_attr = 0777 << 16L

It looks like it sets the permissions to 0777 there.

看起来它将权限设置为0777。

#4


5  

The earlier answers did not work for me (on OS X 10.12). I found that as well as the executable flags (octal 755), I also need to set the "regular file" flag (octal 100000). I found this mentioned here: https://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute

早期的答案对我不起作用(在OS X 10.12上)。我发现,除了可执行的标志(octal 755),我还需要设置“常规文件”标志(octal 100000)。我发现这里提到的是:https://unix.stackexchange.com/questions/14705/zip -formats-external-file-attribute。

A complete example:

一个完整的例子:

zipname = "test.zip"
filename = "test-executable"

zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)

f = open(filename, 'r')
bytes = f.read()
f.close()

info = zipfile.ZipInfo(filename)
info.date_time = time.localtime()
info.external_attr = 0100755 << 16L

zip.writestr(info, bytes, zipfile.ZIP_DEFLATED)

zip.close()

A complete example of my specific usecase, creating a zip of a .app so that everything in the folder Contents/MacOS/ is executable: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

一个完整的例子,我的具体的usecase,创建一个zip的一个。应用程序,以便所有的文件夹内容/MacOS/是可执行的:https://gist.github.com/draknek/3ce889860cea4f59836a79cc11a85。

#5


0  

When you do it like this, does it work alright?

当你这样做的时候,它能正常工作吗?

zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
    f = open(name, 'wb')
    f.write(self.read(name))
    f.close()

If not, I'd suggest throwing in an os.chmod in the for loop with 0777 permissions like this:

如果没有,我建议你扔一个操作系统。chmod在for循环中有0777这样的权限:

zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
    f = open(name, 'wb')
    f.write(self.read(name))
    f.close()
    os.chmod(name, 0777)