2009-01-12 13 views
31

Lorsque j'extraire des fichiers à partir d'un fichier ZIP créé avec le module Python zipfile, tous les fichiers ne sont pas accessibles en écriture, en lecture seule, etc.Comment définir les permissions (attributs) sur un fichier dans un fichier ZIP en utilisant le module zipfile de Python?

Le fichier est créé et extrait sous Linux et Python 2.5.2. Comme le meilleur que je peux dire, je dois définir la propriété ZipInfo.external_attr pour chaque fichier, mais cela ne semble pas être documenté partout où je pourrais trouver, quelqu'un peut-il m'éclairer?

Répondre

33

Cela semble fonctionner (merci Evan, mettant ici si la ligne est dans le contexte):

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

Je voudrais encore voir quelque chose qui documente cette ... Une ressource supplémentaire que j'ai trouvé une note sur le format de fichier Zip: http://www.pkware.com/documents/casestudies/APPNOTE.TXT

+0

Ce serait plus lisible si le tampon, le nom et les octets ont été définis dans l'exemple. –

+0

sûr, ajouté quelques exemples de définitions. – Tom

+8

Pour python 3, vous écrivez ceci '0o777 << 16' –

12

Regardez ceci: Set permissions on a compressed file in python

Je ne suis pas tout à fait sûr que ce soit ce que vous voulez, mais il semble être.

La ligne clé semble être:

zi.external_attr = 0777 << 16L 

On dirait qu'il définit les autorisations à 0777 là.

+0

merci, il a quelques astuces, mais pas vraiment une réponse en tant que telle si ... – Tom

0

Lorsque vous faites comme ça, ça marche bien?

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

Sinon, je proposerais jetais un os.chmod dans la boucle avec 0777 autorisations comme ceci:

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

Je n'utilise pas Python pour extraire le zip, le zip est généré par un serveur web et extrait en utilisant quelque chose sur la machine de l'utilisateur. Dans mon cas, le programme gestionnaire d'archives gnome. – Tom

18

This link a plus d'informations que tout ce que j'ai pu trouver sur le net. Même la source zip n'a rien. Copier la section pertinente pour la postérité. Ce correctif n'est pas vraiment sur la documentation de ce format, qui va juste montrer comment pathétique (lire inexistant) la documentation actuelle est.

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

En outre, this link a également ce qui suit. Ici, l'octet de poids faible signifie probablement l'octet le plus à droite (le plus bas) des quatre octets. Donc, celui-ci est pour MS-DOS et peut probablement être laissé à zéro autrement.

attributs de fichier externe: (4 octets)

 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. 

En outre, le fichier source unix/unix.c dans les sources pour le programme zip de InfoZIP, téléchargé à partir Debian's archives a les éléments suivants dans les commentaires.

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

Donc, en prenant tout cela ensemble, il semble que seul le deuxième octet le plus haut est réellement utilisé, au moins pour Unix.

EDIT: J'ai demandé à propos de l'aspect Unix de ceci sur Unix.SX, à la question "The zip format's external file attribute". On dirait que j'ai eu quelques mauvaises choses. Plus précisément, les deux premiers octets sont utilisés pour Unix.

+0

Certaines des constantes de l'exemple seraient plus lisibles si on utilisait des constantes du module stat (stat.S_IFLNK par exemple). Tout en regardant à travers cela, j'ai trouvé aussi http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727 – Epu

+2

@Epu Techniquement, il n'y a pas de garantie que S_IFLNK sera égal à 0120000 - comme je l'ai mentionné, "Les valeurs Unix sont les mêmes que sur les implémentations UNIX traditionnelles" et en a fourni un exemple mais les valeurs numériques exactes ne sont pas garanties par POSIX (S_IFLNK n'est pas garanti en tant que constante) 0120000 signifie toujours lien symbolique dans un contexte de fichier zip, car il s'agit d'un format multiplateforme. – Random832

5

Les réponses précédentes ne fonctionnaient pas pour moi (sur OS X 10.12). J'ai trouvé que, outre les drapeaux exécutables (octal 755), j'ai aussi besoin de mettre le drapeau "regular file" (octal 100000). J'ai trouvé cet mentionné ici: https://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute

Un exemple complet:

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 exemple complet de mon usecase spécifique, la création d'un zip d'un .app pour que tout dans le dossier Contents/MacOS/ est exécutable: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85