2009-01-12 15 views
31

Cuando extraer archivos de un archivo ZIP creado con el módulo de Python zipfile, todos los archivos no se pueden escribir, sólo lectura, etc.¿Cómo configuro los permisos (atributos) en un archivo en un archivo ZIP usando el módulo zipfile de Python?

El archivo se crea y se extrajo con Linux y Python 2.5.2.

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

Respuesta

33

Esto parece funcionar (gracias Evan, ponerlo 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 documenta esto ... Un recurso adicional que encontré fue una nota en el formato de archivo Zip: http://www.pkware.com/documents/casestudies/APPNOTE.TXT

+0

Esto sería más legible si el buffer, nombre y bytes se definieron en el ejemplo. –

+0

seguro, agregó algunas definiciones de ejemplo. – Tom

+8

Para Python 3, debe escribir esto '0o777 << 16' –

12

vistazo a esto: Set permissions on a compressed file in python

no estoy del todo seguro de si eso es lo que quiere, pero parece ser.

La línea clave parece ser:

zi.external_attr = 0777 << 16L 

Parece que establece los permisos a 0777 allí.

+0

gracias, tiene algunos consejos, pero en realidad no es una respuesta como tal ... – Tom

0

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 es así, me gustaría sugerir tirando en una os.chmod en el bucle for con los permisos 0777 de esta manera:

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) 
+0

No estoy usando Python para extraer el archivo comprimido, el archivo zip es generado por un servidor web y extraído usando algo en la máquina del usuario. En mi caso, el programa administrador de archivos gnome. – Tom

18

This link tiene más información que cualquier otra cosa que he podido encontrar en la red. Incluso la fuente zip no tiene nada. Copiando la sección relevante para la posteridad. Este parche no se trata realmente de documentar este formato, lo que demuestra cuán patética (es decir, inexistente) 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, this link tiene lo siguiente. Aquí, el byte de orden inferior 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, presumiblemente, se puede dejar en cero. atributos

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 de Unix/unix.c en las fuentes de programa de compresión de InfoZip, descargado de Debian's archives tiene la 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. 
    */ 

Tomando todo esto en conjunto, parece que solo se utiliza realmente el segundo byte más alto, al menos para Unix.

EDIT: Pregunté sobre el aspecto Unix de esto en Unix.SX, en la pregunta "The zip format's external file attribute". Parece que tengo un par de cosas mal. Específicamente, los dos bytes superiores se usan para Unix.

+0

Algunas de las constantes en el ejemplo serían más legibles si se usan constantes del módulo de estadísticas (stat.S_IFLNK, por ejemplo). Mientras miraba a través de esto, encontré también http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727 – Epu

+2

@Epu Técnicamente, no hay garantía de que S_IFLNK sea igual a 0120000 - como mencioné, "Los valores de Unix son los mismos que en las implementaciones de Unix tradicionales" y proporcionó un ejemplo de uno, pero los valores numéricos exactos no están garantizados por POSIX (ni está garantizado que S_IFLNK exista como una constante) pero 0120000 siempre significa enlace simbólico en un contexto zip debido a que es un formato multiplataforma. – Random832

5

Las respuestas anteriores no me funcionaron (en OS X 10.12). Descubrí que, además de los indicadores ejecutables (octal 755), también necesito establecer el indicador de "archivo normal" (octal 100000). Me pareció que esta 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 una postal de un .app para que todo en la carpeta Contents/MacOS/ es ejecutable: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

Cuestiones relacionadas