¿Cómo configuro los permisos (atributos) en un archivo en un archivo ZIP usando el módulo zipfile de Python?

Cuando zipfile archivos de un archivo ZIP creado con el módulo zipfile Python, todos los archivos no son de escritura, solo de lectura, etc.

El archivo se está creando y extrayendo bajo Linux y Python 2.5.2.

Lo mejor que puedo decir, necesito establecer la propiedad ZipInfo.external_attr para cada archivo, pero esto no parece estar documentado en ningún lugar que pueda encontrar, ¿alguien me puede aclarar?

Esto parece funcionar (gracias Evan, poniéndolo aquí para que la línea esté en 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() 

Todavía me gustaría ver algo que documente esto ... Un recurso adicional que encontré fue una nota en el formato de archivo Zip: http://www.pkware.com/documents/casestudies/APPNOTE.TXT

Este enlace tiene más información que cualquier otra cosa que haya podido encontrar en la red. Incluso la fuente zip no tiene nada. Copiando la sección correspondiente a la posteridad. Este parche no es realmente acerca de la documentación de este formato, que solo sirve para mostrar qué tan patética (no existe) es la documentación actual.

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

Además, este enlace tiene lo siguiente. Aquí, el byte de orden bajo presumiblemente significa el byte más a la derecha (el más bajo) de los cuatro bytes. Así que este es para MS-DOS y probablemente se puede dejar como cero de lo contrario.

Atributos del archivo 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. 

Además, el archivo fuente unix / unix.c en las fonts para el progtwig zip de InfoZIP, descargado de los archivos de Debian tiene lo siguiente en los comentarios.

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

Entonces, al tomar todo esto en conjunto, parece que en realidad solo se usa el segundo byte más alto, al menos para Unix.

EDITAR: Le pregunté sobre el aspecto de Unix de esto en Unix.SX, en la pregunta " El atributo del archivo externo del formato zip ". Parece que me equivoqué un par de cosas. Específicamente, los dos bytes superiores se utilizan para Unix.

Mira esto: establece permisos en un archivo comprimido en Python

No estoy completamente seguro de si eso es lo que quieres, pero parece ser.

La línea clave parece ser:

 zi.external_attr = 0777 << 16L 

Parece que establece los permisos para 0777 allí.

Las respuestas anteriores no funcionaron para mí (en OS X 10.12). Encontré que, además de los indicadores ejecutables (octal 755), también necesito establecer el indicador “archivo regular” (octal 100000). Encontré esto mencionado aquí: https://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute

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

Un ejemplo completo de mi caso de uso específico, creando un zip de un .app para que todo en la carpeta Contents/MacOS/ sea ​​ejecutable: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

Puede extender la clase ZipFile para cambiar el permiso de archivo predeterminado:

 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 ejemplo cambia el permiso de archivo predeterminado a 664 y conserva 775 para los directorios.

Código relacionado:

  • ZipFile.writestr , Python 2.7
  • ZipFile.writestr , Python 3.6

Cuando lo haces así, ¿funciona bien?

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

Si no, sugeriría os.chmod un os.chmod en el bucle for con 0777 permisos como este:

 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) 

También mire lo que hace el módulo zipfile de Python :

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

`` `