Come posso impostare le autorizzazioni (attributi) su un file in un file ZIP usando il modulo zipfile Python?
-
10-07-2019 - |
Domanda
Quando estraggo file da un file ZIP creato con Python zipfile
, tutti i file non sono scrivibili, di sola lettura ecc.
Il file viene creato ed estratto in Linux e Python 2.5.2.
Come meglio posso dire, ho bisogno di impostare la proprietà ZipInfo.external_attr
per ogni file, ma questo non sembra essere documentato ovunque io possa trovare, qualcuno può illuminarmi?
Soluzione
Questo sembra funzionare (grazie Evan, mettendolo qui in modo che la linea sia nel contesto):
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()
Mi piacerebbe ancora vedere qualcosa che documentasse questo ... Un'ulteriore risorsa che ho trovato era una nota sul formato del file Zip: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
Altri suggerimenti
Questo link contiene più informazioni di qualunque altra cosa in grado di trovare in rete. Anche la fonte zip non ha nulla. Copia della sezione pertinente per i posteri. Questa patch non riguarda davvero la documentazione di questo formato, il che dimostra semplicemente quanto sia patetica (leggi inesistente) la documentazione attuale.
# 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, '')
Inoltre, questo link ha il seguente. Qui il byte di ordine inferiore presumibilmente significa il byte più basso (più basso) dei quattro byte. Quindi questo è per MS-DOS e presumibilmente può essere lasciato come zero altrimenti.
attributi file esterni: (4 byte)
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.
Inoltre, il file sorgente unix / unix.c nei sorgenti per il programma zip di InfoZIP, scaricato da L'archivio di Debian contiene i seguenti commenti.
/* 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.
*/
Quindi, tenendo tutto insieme, sembra che venga utilizzato solo il secondo byte più alto, almeno per Unix.
EDIT: ho chiesto dell'aspetto Unix di questo su Unix.SX, nella domanda " L'attributo del file esterno del formato zip " ;. Sembra che ho sbagliato un paio di cose. In particolare entrambi i primi due byte sono usati per Unix.
Guarda questo: Imposta le autorizzazioni su un file compresso in Python
Non sono del tutto sicuro se è quello che vuoi, ma sembra essere.
La linea chiave sembra essere:
zi.external_attr = 0777 << 16L
Sembra che imposta le autorizzazioni su 0777
lì
Le risposte precedenti non funzionavano per me (su OS X 10.12). Ho scoperto che oltre ai flag eseguibili (ottale 755), devo anche impostare il "file normale" bandiera (ottale 100000). Ho trovato questo menzionato qui: https://unix.stackexchange.com/questions/ 14705 / il-zip-formati-esterni-file-attributo
Un esempio 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 esempio completo della mia specifica base utente, la creazione di un file zip di un file .app in modo che tutto nella cartella Sommario / MacOS /
sia eseguibile: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85
È possibile estendere la classe ZipFile
per modificare l'autorizzazione del file predefinito:
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)
Questo esempio modifica l'autorizzazione del file predefinito in 664
e mantiene 775
per le directory.
Codice correlato:
Quando lo fai in questo modo, funziona bene?
zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
f = open(name, 'wb')
f.write(self.read(name))
f.close()
In caso contrario, suggerirei di inserire un os.chmod
nel ciclo for con 0777 autorizzazioni come questa:
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)
Guarda anche cosa Modulo zipfile di 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
...
`` `