Как установить права доступа (атрибуты) для файла в ZIP-файле с помощью модуля Python zipfile?
Когда я извлекаю файлы из ZIP-файла, созданного с помощью Python zipfile
модуль, все файлы недоступны для записи, только для чтения и т. д.
Файл создается и распаковывается под Linux и Python 2.5.2.
Как я могу сказать, мне нужно установить ZipInfo.external_attr
свойство для каждого файла, но это, кажется, не документировано, где я мог найти, может кто-нибудь просветить меня?
8 ответов
Кажется, это работает (спасибо Эван, поместив это здесь так, чтобы строка была в контексте):
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()
Я все еще хотел бы видеть кое-что, что документирует это... Дополнительный ресурс, который я нашел, был примечанием о формате файла Zip: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
Эта ссылка содержит больше информации, чем что-либо еще, что я смог найти в сети. Даже у zip-источника ничего нет. Копирование соответствующего раздела для потомков. Этот патч на самом деле не предназначен для документирования этого формата, он просто показывает, насколько патетической (читай несуществующей) является текущая документация.
# 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, '')
Также эта ссылка имеет следующее. Здесь младший байт предположительно означает самый правый (младший) байт из четырех байтов. Так что это для MS-DOS и, по-видимому, в противном случае его можно оставить равным нулю.
атрибуты внешнего файла: (4 байта)
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.
Кроме того, исходный файл unix/unix.c в источниках для zip-программы InfoZIP, загруженный из архивов Debian, содержит следующее в комментариях.
/* 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.
*/
Итак, взяв все это вместе, похоже, что фактически используется только второй старший байт, по крайней мере, для Unix.
РЕДАКТИРОВАТЬ: я спросил об аспекте Unix этого на Unix.SX, в вопросе " Атрибут внешнего файла формата zip". Похоже, я неправильно понял пару вещей. В частности, оба верхних байта используются для Unix.
Посмотрите на это: Установите права на сжатый файл в Python
Я не совсем уверен, что ты этого хочешь, но, похоже, так и есть.
Ключевая строка выглядит так:
zi.external_attr = 0777 << 16L
Похоже, он устанавливает права на 0777
там.
Предыдущие ответы не работали для меня (на OS X 10.12). Я обнаружил, что помимо флагов исполняемого файла (восьмеричное число 755) мне также нужно установить флаг "обычный файл" (восьмеричное число 100000). Я нашел это упомянутое здесь: https://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute
Полный пример:
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()
Полный пример моего конкретного сценария использования, создание почтового индекса.app, чтобы все в папке Contents/MacOS/
это исполняемый файл: https://gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85
Вы можете продлить ZipFile
класс для изменения разрешения по умолчанию для файла:
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)
В этом примере изменяется разрешение файла по умолчанию на 664
и держит 775
для каталогов.
Связанный код:
ZipFile.writestr
Python 2.7ZipFile.writestr
Python 3.6
Чтобы установить разрешения (атрибуты Unix) для файла в ZIP-файле с помощью модуля Python zipfile, передайте атрибуты как биты 16-31 external_attr ZipInfo.
Модуль zipfile Python принимает 16-битное поле "Mode" (в котором хранится поле st_mode из struct stat, содержащее права пользователя / группы / другие, setuid / setgid, информацию о символической ссылке и т. Д.) Дополнительного блока ASi для Unix в битах external_attr вышеупомянутый.
Вы также можете импортировать модуль "stat" Python, чтобы получить определения констант режима.
Вы также можете установить 3 в create_system, чтобы указать операционную систему, создавшую ZIP-архив: 3 = Unix; 0 = Windows.
Вот пример:
#!/usr/bin/python
import stat
import zipfile
def create_zip_with_symlink(output_zip_filename, link_source, link_target):
zipInfo = zipfile.ZipInfo(link_source)
zipInfo.create_system = 3
unix_st_mode = stat.S_IFLNK | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH
zipInfo.external_attr = unix_st_mode << 16
zipOut = zipfile.ZipFile(output_zip_filename, 'w', compression=zipfile.ZIP_DEFLATED)
zipOut.writestr(zipInfo, link_target)
zipOut.close()
create_zip_with_symlink('cpuinfo.zip', 'cpuinfo.txt', '/proc/cpuinfo')
Также посмотрите, что делает модуль Python zipfile:
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
...
`` `
Когда вы делаете это так, это работает нормально?
zf = zipfile.ZipFile("something.zip")
for name in zf.namelist():
f = open(name, 'wb')
f.write(self.read(name))
f.close()
Если нет, я бы предложил бросить в os.chmod
в цикле for с разрешениями 0777, например:
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)