deniz.in

Piyasalar

Hava durumu

Hava durumu yükleniyor

· kaynak Hacker News – Front Page (native)

cat ile birleştirilen .tar.gz dosyaları neden bozuk bir arşiv üretir

Bir geliştiricinin .tar.gz arşivlerini cat ile birleştirme girişimi, tar'ın manyetik bant döneminden kalma EOF işaretçileri ile gzip'in çok üyeli yapısının nasıl çakıştığını ortaya çıkardı. Çözüm, arşivleri üye üye yeniden oluşturmayı gerektiriyor.

cat ile birleştirilen .tar.gz dosyaları neden bozuk bir arşiv üretir

Hata biçimi

Bir proje birden fazla .tar.gz arşivi üretiyor ve bunların tek bir dosyaya dönüşmesi gerekiyorsa, cat üzerinden borulamak en bariz hareket gibi görünür. Geliştirici Alex Chan tam olarak bunu denedi ve sonucun bozuk olduğunu gördü: birleştirilmiş dosya açıldı, ancak yalnızca ilk arşivin içeriği göründü. Hacker News'in ana sayfasına ulaşan bir blog yazısında Chan bunun sebebini inceliyor ve açıklama manyetik bant donanımından ve 1990'ların patent hukukundan geçiyor.

tar, bant sürücüsü mirasını taşır

tar, tape archive kısaltmasıdır; birden fazla dosyayı, üstverileriyle — adlar, zaman damgaları, dizin düzeni — birlikte tek bir akışa paketler. Chan'a göre format, kendisi için tasarlandığı manyetik bantların fiziksel sınırlarını hâlâ yansıtıyor: verilerin sırayla okunması gerekiyordu, yazma işlemleri yalnızca ekleme biçimindeydi ve bantlar sabit blok boyutları kullanıyordu.

Dahili olarak bir arşiv, her dosyayı dosya adı ve boyut gibi üstverileri taşıyan bir başlık bloğu, ardından içeriği tutan veri blokları olarak saklar. Arşiv daha sonra tamamen sıfırlarla dolu en az iki blokla kapanır. Bu bloklar bir dosya sonu işaretçisi görevi görür: okuyucu sonrasındaki her şeyi boş bant olarak değerlendirir ve yok sayar. GNU tar'a --ignore-zeros bayrağıyla okumaya devam etmesi söylenebilir, ancak Chan'ın belirttiği gibi, genel dağıtım için hazırlanan arşivlerin varsayılan ayarlarla doğru şekilde açılması gerekir.

Bu yapı, bilinen bazı tar tuhaflıklarını da açıklar. Dosya boyutları, herhangi bir veri yazılmadan önce başlıkta bildirilmek zorundadır — Chan, Python'ın TarFile.addfile fonksiyonunu kullanırken tarinfo.size değerini ayarlamayı defalarca unuttuğunu, bunun da boş girdiler ürettiğini anlatıyor. Arşivler meşru olarak yinelenen dosya adları da içerebilir: bant yeniden yazılamadığı için bir dosyayı güncellemek, aynı adla yeni bir sürüm eklemek anlamına geliyordu ve çıkarma işleminde sonraki kopya öncekinin üzerine yazıyor.

gzip birleştirebilir çünkü EOF işaretçisi yoktur

gzip ise buna karşılık tek bir akışı kayıpsız sıkıştırır. RFC 1952'de tanımlanan tasarımı, donanımdan çok dönem yasal ve bellek kısıtlamalarıyla şekillendi: LZW algoritması patentli olduğu için compress'in patentsiz bir alternatifi olarak yazıldı, küçük ve sınırlı bellekte çalışması gerekiyordu ki veri kesintisiz parçalarla işlenebilsin, ve CPU'lar ile işletim sistemleri arasında taşınabilir olmalıydı.

Bir gzip dosyası, her biri kendi başlığına, sıkıştırılmış verisine ve bir CRC32 sağlama toplamı ile sıkıştırılmamış boyutu içeren bir kuyruk bloğuna sahip bir veya daha fazla üyeden oluşur. Dosya sonu işaretçisi yoktur ve — Chan'ın vurguladığı gibi — üyeler dosyalara benzer değildir. Araçlar bunları tek bir kesintisiz veri akışı olarak ele alır, bu yüzden üyeleri tek tek listeleyemez veya çıkaramazsınız. Pratik sonuç: ayrı .gz dosyalarını cat ile birleştirmek geçerli bir dosya üretir ve gunzip birleşik sıkıştırılmamış veriyi tek bir akış olarak döndürür.

İki formatın çakıştığı yer

Bir .tar.gz dosyası iki formatı üst üste dizer: tar bir dizin ağacını akışa dönüştürür, gzip bu akışı küçültür. İkisi de sırayla okunur; birleşimin ağ üzerinden iyi akmasının nedeni de budur — dosyalar, indirme tamamlanmadan, ulaştıkça işlenebilir.

tar.gz dosyalarını cat ile birleştirmek, ikisinin arasındaki dikiş yerinde başarısız olur. gzip katmanı birleştirilmiş üyeleri kabul eder ve şikâyet etmeden açar, ancak tar sonuçtaki akışı okurken ilk arşivin sıfır bloklu EOF işaretçisiyle karşılaşır ve durur. gzip memnuniyetle devam edecek olsa da, ilk arşivden sonraki her şey sessizce atılır.

Çözüm: arşivi yeniden oluşturmak

Chan, baytları birbirine dikmek yerine, Python'ın tarfile modülünü kullanarak arşivleri üye üye birleştiriyor. Her girdi r:gz modunda açılır, üyeleri getmembers ile gezilir ve her girdi w:gz modunda açılan taze bir arşive kopyalanır. Sonuç, tek bir EOF işaretçisine sahip ve varsayılan olmayan okuyucu bayraklarına dayanmayan tek bir geçerli arşivdir. Basit bir birleştirmeden daha fazla koddur, ancak her aracın kutudan çıktığı gibi okuyabileceği bir arşiv üreten tek yaklaşım budur.

Neden önemli

Hata sessizdir ve tehlikeli kılan da budur. Birleştirilmiş bir .tar.gz herhangi bir hata vermeden açılır, böylece pipeline'lar ve hızlı tekdüze kontroller geçebilirken ilk arşivden sonraki her şey kaybolur — bu, parçalar halinde arşiv üreten veya build artifact'lerini birleştiren herkes için gerçek bir tehlikedir. Her iki formatın da iç yapısını anlamak, zorunlu ön dosya boyutlarından yinelenen adların üzerine yazılmasına kadar günlük tar davranışının gizemini de çözer. Ve --ignore-zeros, ardında veri taşıyan arşivler için bir çıkış kapısı sunsa da, yalnızca özel bir bayrakla doğru açılan dosyaları dağıtmak, çoğu projenin kaçınması gereken kırılgan bir ödündür.

  • #tar
  • #gzip
  • #file-formats
  • #python
  • #compression