web-dev-qa-db-ja.com

Pythonのzipfileモジュールを使用してZipファイル内のファイルに権限(属性)を設定するにはどうすればよいですか?

Python zipfile モジュールで作成されたZipファイルからファイルを抽出すると、すべてのファイルが書き込み可能ではなく、読み取り専用などになります。

このファイルは、LinuxおよびPython 2.5.2で作成および抽出されています。

私が知る限り、ファイルごとにZipInfo.external_attrプロパティを設定する必要がありますが、これはどこにでも文書化されていないようです。誰かが私を教えてくれますか?

43
Tom

これはうまくいくようです(Evanに感謝します。ここに配置して、行がコンテキストに含まれるようにします)。

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

44
Tom

このリンク 私がネット上で見つけた他の何よりも多くの情報があります。 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, '')

また、 this link には以下が含まれます。ここで、下位バイトはおそらく4バイトの右端(最下位)のバイトを意味します。したがって、これは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.

また、InfoZIPのZipプログラムのソースにあるソースファイルunix/unix.cは、 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では、2番目に高いバイトのみが実際に使用されているように見えます。

編集:私は、Unix.SXでのこのUnixの側面について、「 Zip形式の外部ファイル属性 」という質問で尋ねました。いくつか問題があったようです。具体的には、上位2バイトの両方がUnixに使用されます。

24
Faheem Mitha

これを見てください: Pythonで圧縮ファイルに権限を設定してください

それがあなたの望むものかどうかは完全にはわかりませんが、そうだと思われます。

キーラインは次のように見えます。

zi.external_attr = 0777 << 16L

そこで、権限を0777に設定しているようです。

13
Evan Fosmark

以前の回答は私には機能しませんでした(OS X 10.12)。実行可能フラグ(8進数の755)だけでなく、「通常のファイル」フラグ(8進数の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のZipを作成して、フォルダーContents/MacOS/実行可能ファイル: https://Gist.github.com/Draknek/3ce889860cea4f59838386a79cc11a85

7
Alan Hazelden

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をディレクトリに保持します。

関連コード:

2
Soroush

このようにすると、うまくいきますか?

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

そうでない場合は、次のような0777権限でforループにos.chmodをスローすることをお勧めします。

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
Evan Fosmark

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

`` `

0
thakis