これは、GZIPストリームの非圧縮サイズを決定します:
#!/usr/bin/python
import sys
import zlib
f = open(sys.argv[1], "rb")
z = zlib.decompressobj(15+16)
total = 0
while True:
buf = z.unconsumed_tail
if buf == "":
buf = f.read(1024)
if buf == "":
break
got = z.decompress(buf, 4096)
if got == "":
break
total += len(got)
print total
if z.unused_data != "" or f.read(1024) != "":
print "warning: more input after end of gzip stream"
これは、抽出されたときでtarファイル内のすべてのファイルのために必要なスペースのわずかな過大評価を返します。長さには、これらのファイル、およびtarディレクトリー情報が含まれます。
gzip.pyコードは、入力データのサイズを除いて、圧縮解除されたデータの量を制御しません。 gzip.pyでは、一度に1024圧縮バイトを読み込みます。圧縮されていないデータ(1032 * 1024、ここで1032:1はdeflateの圧縮率の最大値)に対して最大約1056768バイトのメモリ使用量でOKならgzip.pyを使用できます。ここでの解法は、圧縮されていないデータの量を制限する第2引数を使用してzlib.decompress
を使用します。 gzip.pyはそうではありません。
これは正確にtar形式をデコードすることにより抽出されたタールエントリの合計サイズを決定します:
#!/usr/bin/python
import sys
import zlib
def decompn(f, z, n):
"""Return n uncompressed bytes, or fewer if at the end of the compressed
stream. This only decompresses as much as necessary, in order to
avoid excessive memory usage for highly compressed input.
"""
blk = ""
while len(blk) < n:
buf = z.unconsumed_tail
if buf == "":
buf = f.read(1024)
got = z.decompress(buf, n - len(blk))
blk += got
if got == "":
break
return blk
f = open(sys.argv[1], "rb")
z = zlib.decompressobj(15+16)
total = 0
left = 0
while True:
blk = decompn(f, z, 512)
if len(blk) < 512:
break
if left == 0:
if blk == "\0"*512:
continue
if blk[156] in ["1", "2", "3", "4", "5", "6"]:
continue
if blk[124] == 0x80:
size = 0
for i in range(125, 136):
size <<= 8
size += blk[i]
else:
size = int(blk[124:136].split()[0].split("\0")[0], 8)
if blk[156] not in ["x", "g", "X", "L", "K"]:
total += size
left = (size + 511) // 512
else:
left -= 1
print total
if blk != "":
print "warning: partial final block"
if left != 0:
print "warning: tar file ended in the middle of an entry"
if z.unused_data != "" or f.read(1024) != "":
print "warning: more input after end of gzip stream"
あなたは爆弾のためのtarファイルをスキャンするこのバリアントを使用することができます。これには、ヘッダ情報のサイズを大きくして、そのデータを圧縮解除する必要があるという利点があります。
.tar.bz2アーカイブの場合、Python bz2ライブラリ(少なくとも3.3以降)は、あまりにも多くのメモリを消費するbz2爆弾にとって不可避的に安全ではありません。 bz2.decompress
関数は、zlib.decompress
のように2番目の引数を提供しません。これは、ランレングスコーディングにより、bz2フォーマットがzlibよりもはるかに高い最大圧縮率を持つという事実によって、さらに悪化しています。 bzip2は、1 GBのゼロを722バイトに圧縮します。したがって、のように、入力を2番目の引数なしで計測することによって、bz2.decompress
の出力を計測することはできません。解凍された出力サイズに制限がないことは、Pythonインターフェイスの基本的な欠陥です。
3.3の_bz2module.cを調べて、この問題を避けるために文書化されていない方法があるかどうかを確認しました。その周りに道はない。 decompress
関数は、提供されたすべての入力を解凍できるまで、結果バッファを増やし続けます。 _bz2module.cを修正する必要があります。
TarInfo.sizeを使用できませんか? – fatfredyy
@fatfredyyあなたはタールを解凍する前にgz爆弾を打つことができます。 – Jakozaur
あなたは爆弾の効果を心配していますか?メモリ使用量のみ?抽出されたディスクスペースの使用量(参照された質問ごと) –