Como faço para definir permissões (atributos) em um arquivo em um arquivo ZIP usando o módulo zipfile do Python?

StackOverflow https://stackoverflow.com/questions/434641

Pergunta

Quando eu extrair arquivos de um arquivo ZIP criado com o Python zipfile módulo, todos os arquivos não são graváveis, somente leitura etc.

O arquivo está sendo criado e extraídas sob Linux e Python 2.5.2.

Como melhor eu posso dizer, eu preciso definir a propriedade ZipInfo.external_attr para cada arquivo, mas isso não parece ser documentado em qualquer lugar que eu poderia encontrar, alguém pode me esclarecer?

Foi útil?

Solução

Isso parece funcionar (graças Evan, colocá-lo aqui para que a linha está em contexto):

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()

Eu ainda gostaria de ver algo que os documentos isso ... Um recurso adicional que eu encontrei foi uma nota sobre o formato de arquivo Zip: http://www.pkware.com/documents/casestudies/APPNOTE.TXT

Outras dicas

Este link tem mais informação do que qualquer outra coisa que eu estive capaz de encontrar na net. Mesmo a fonte zip não tem nada. Copiando a seção relevante para a posteridade. Este patch não é realmente sobre documentar este formato, o que só serve para mostrar quão patético (leia-se inexistente) a documentação atual.

# 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, '')

Além disso, este link tem a seguinte. Aqui, o byte baixo ordem presumivelmente significa que o (menor) de byte mais à direita dos quatro bytes. Então, este é para MS-DOS e pode presumivelmente ser deixada como zero nos outros casos.

atributos arquivo externo: (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.

Além disso, o arquivo de origem unix / unix.c nas fontes para o programa de zip de InfoZip, baixado arquivos do Debian tem a seguinte nos comentários.

  /* 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.
   */

Assim, tendo tudo isso junto, parece que apenas o segundo mais alto byte é realmente usado, pelo menos para Unix.

EDIT: Eu perguntei sobre o aspecto Unix desta em Unix.SX, na pergunta " arquivo externo atributo do formato zip". Parece que eu tenho um par de coisas erradas. Especificamente, tanto da parte superior dois bytes são usados ??para Unix.

Olhe para isto: Definir permissões em um arquivo compactado em Python

Eu não estou totalmente certo se é isso que você quer, mas ela parece ser.

A linha de chave parece ser:

zi.external_attr = 0777 << 16L

Parece que define as permissões para 0777 lá.

As respostas anteriores não funcionou para mim (no OS X 10.12). Descobri que, assim como as bandeiras executáveis ??(octal 755), eu também preciso para definir o sinalizador "arquivo regular" (octal 100000). Eu encontrei este mencionado aqui: https://unix.stackexchange.com/questions/ 14705 /-the-zip-formatos-external-arquivo de atributos

Um exemplo completo:

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()

Um exemplo completo do meu usecase específica, criando um zip de um .app para que tudo na Contents/MacOS/ pasta é executável: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

Você pode estender a classe ZipFile para alterar a permissão de arquivo padrão:

from zipfile import ZipFile, ZipInfo
import time

class PermissiveZipFile(ZipFile):
    def writestr(self, zinfo_or_arcname, data, compress_type=None):
        if not isinstance(zinfo_or_arcname, ZipInfo):
            zinfo = ZipInfo(filename=zinfo_or_arcname,
                            date_time=time.localtime(time.time())[:6])

            zinfo.compress_type = self.compression
            if zinfo.filename[-1] == '/':
                zinfo.external_attr = 0o40775 << 16   # drwxrwxr-x
                zinfo.external_attr |= 0x10           # MS-DOS directory flag
            else:
                zinfo.external_attr = 0o664 << 16     # ?rw-rw-r--
        else:
            zinfo = zinfo_or_arcname

        super(PermissiveZipFile, self).writestr(zinfo, data, compress_type)

Este exemplo altera a permissão de arquivo padrão para 664 e mantém 775 para diretórios.

código relacionadas:

Quando você faz assim, ele funciona bem?

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

Se não, eu sugiro jogando em uma os.chmod no loop for com 0777 permissões como esta:

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)

Também olhar para o que Python do zipfile módulo faz:

def write(self, filename, arcname=None, compress_type=None):
    ...
    st = os.stat(filename)
    ...
    zinfo = ZipInfo(arcname, date_time)
    zinfo.external_attr = (st[0] & 0xFFFF) << 16L      # Unix attributes
    ...

`` `

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top