2009-01-12 14 views
31

Kiedy wyodrębnić pliki z pliku ZIP stworzony z modułem Pythona zipfile wszystkie pliki nie są zapisu, tylko do odczytu itpJak ustawić uprawnienia (atrybuty) do pliku w pliku ZIP za pomocą modułu zipfile Pythona?

Plik jest tworzony i ekstrahowano pod Linuksem i Python 2.5.2.

Jak najlepiej mogę powiedzieć, muszę ustawić właściwość ZipInfo.external_attr dla każdego pliku, ale nie wydaje mi się, że jest to dokumentowane gdziekolwiek mogę znaleźć, czy ktoś może mnie oświecić?

Odpowiedz

33

To wydaje się działać (dzięki Evan, stawiając go tutaj więc linia jest w kontekście):

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

wciąż chciałbym zobaczyć coś, co dokumentuje ten ... Dodatkowym źródłem znalazłem notatka w formacie pliku Zip: http://www.pkware.com/documents/casestudies/APPNOTE.TXT

+0

Byłoby to bardziej czytelne, gdyby zdefiniowano bufor, nazwę i bajty w przykładzie. –

+0

Na pewno dodano kilka przykładowych definicji. – Tom

+8

Dla Pythona 3, napiszesz to '0o777 << 16' –

12

Spójrz na to: Set permissions on a compressed file in python

Nie jestem do końca pewien, czy to, co chcesz, ale to wydaje się być.

Kluczem wydaje się być linia:

zi.external_attr = 0777 << 16L 

Wygląda na to ustawia uprawnienia do 0777 tam.

+0

dziękuję, ma pewne wskazówki, ale nie tak naprawdę odpowiedź jako taka ... – Tom

0

Kiedy robisz to w ten sposób, działa poprawnie?

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

Jeśli nie, to bym Proponuję rzucać w os.chmod w pętli for z 0777 uprawnieniach tak:

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

Nie używam Pythona do rozpakowania pliku ZIP, zip jest generowany przez serwer WWW i wyodrębniany za pomocą czegoś na komputerze użytkownika. W moim przypadku program do zarządzania archiwum gnomów. – Tom

18

This link ma więcej informacji niż cokolwiek innego, udało mi się znaleźć na sieć. Nawet źródło zip nie ma nic. Kopiowanie odpowiedniej sekcji dla potomności. Ta poprawka tak naprawdę nie polega na dokumentowaniu tego formatu, co pokazuje, jak żałosna (czytaj nieistniejąca) jest aktualna dokumentacja.

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

Również, this link ma następujące. Tutaj bajt niskiego rzędu prawdopodobnie oznacza prawy (najniższy) bajt czterech bajtów. Tak więc ten jest dla MS-DOS i prawdopodobnie można go pozostawić jako zero w przeciwnym razie. Atrybuty

plik zewnętrzny (4 bajty)

 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. 

Również plik źródłowy UNIX/unix.c w źródłach programu zip InfoZip za pobrane od Debian's archives ma następujące w komentarzach.

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

Tak więc biorąc pod uwagę to wszystko, wygląda na to, że jest używany tylko drugi najwyższy bajt, przynajmniej dla Uniksa.

EDYCJA: Pytałem o Unixowy aspekt tego na Unix.SX, w pytaniu "The zip format's external file attribute". Wygląda na to, że mam kilka złych rzeczy. W szczególności oba dwa najwyższe bajty są używane w systemie Unix.

+0

Niektóre stałe w przykładzie będą bardziej czytelne, jeśli zostaną użyte stałe z modułu stat (np. Stat.S_IFLNK). Przeglądając to, znalazłem także http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727 – Epu

+2

@Epu Technicznie nie ma gwarancji, że S_IFLNK będzie równy 0120000 - jak już wspomniałem, "Wartości Unix są takie same jak w tradycyjnych implementacjach unixa" i dostarczają przykładu od jednego, ale dokładne wartości liczbowe nie są gwarantowane przez POSIX (ani S_IFLNK faktycznie nie gwarantują istnienia jako stała), ale 0120000 zawsze oznacza dowiązanie symboliczne w kontekście zip, ponieważ jest to format wieloplatformowy. – Random832

5

Wcześniejsze odpowiedzi nie działały dla mnie (na OS X 10.12). Zauważyłem, że oprócz flag wykonywalnych (ósemkowy 755), muszę również ustawić flagę "plik regularny" (ósemkowy 100000). Znalazłem tu wymienić: https://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute

Kompletny przykład:

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

Kompletny przykład mojej konkretnej usecase, tworząc zip o .app tak, że wszystko w folderze Contents/MacOS/ jest wykonywalny: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

Powiązane problemy