2013-03-02 18 views
5

Po prostu eksperymentowałem z archiwami/tar i compress/gzip, do automatycznego przetwarzania niektórych kopii zapasowych, które mam.Dlaczego mieszanie md5 z tar-części tar.gz przez TeeReader jest złe?

Mój problem polega na tym, że mam różne pliki .tar i pliki .tar.gz unoszące się wokół, a tym samym chcę wyodrębnić hash (md5) z pliku .tar.gz, a hash (md5) z plik .tar, najlepiej w jednym przebiegu.

Przykładowy kod, jaki do tej pory, działa doskonale dla skrótów plików w .tar.gz oraz dla .gz, ale skrót dla .tar jest błędny i nie mogę się dowiedzieć Jaki jest problem.

Spojrzałem na plik tar/reader.go i zobaczyłem, że jest tam trochę przeskoków, ale myślałem, że wszystko powinno przebiegać nad interfejsem io.Reader, a tym samym TeeReader powinien nadal przechwytywać wszystkie bajty.

package main 

import (
    "archive/tar" 
    "compress/gzip" 
    "crypto/md5" 
    "fmt" 
    "io" 
    "os" 
) 

func main() { 
    tgz, _ := os.Open("tb.tar.gz") 
    gzMd5 := md5.New() 
    gz, _ := gzip.NewReader(io.TeeReader(tgz, gzMd5)) 
    tarMd5 := md5.New() 
    tr := tar.NewReader(io.TeeReader(gz, tarMd5)) 
    for { 
     fileMd5 := md5.New() 
     hdr, err := tr.Next() 
     if err == io.EOF { 
      break 
     } 
     io.Copy(fileMd5, tr) 
     fmt.Printf("%x %s\n", fileMd5.Sum(nil), hdr.Name) 
    } 
    fmt.Printf("%x tb.tar\n", tarMd5.Sum(nil)) 
    fmt.Printf("%x tb.tar.gz\n", gzMd5.Sum(nil)) 
} 

teraz na poniższym przykładzie:

$ echo "a" > a.txt 
$ echo "b" > b.txt 
$ tar cf tb.tar a.txt b.txt 
$ gzip -c tb.tar > tb.tar.gz 
$ md5sum a.txt b.txt tb.tar tb.tar.gz 

60b725f10c9c85c70d97880dfe8191b3 a.txt 
3b5d5c3712955042212316173ccf37be b.txt 
501352dcd8fbd0b8e3e887f7dafd9392 tb.tar 
90d6ba204493d8e54d3b3b155bb7f370 tb.tar.gz 

Na Linux Mint 14 (bazuje na Ubuntu 12.04) z przejść 1.02 z Ubuntu repozytoriów wynik dla mojego programu Go jest:

$ go run tarmd5.go 
60b725f10c9c85c70d97880dfe8191b3 a.txt 
3b5d5c3712955042212316173ccf37be b.txt 
a26ddab1c324780ccb5199ef4dc38691 tb.tar 
90d6ba204493d8e54d3b3b155bb7f370 tb.tar.gz 

Wszystkie hasze z wyjątkiem tb.tar są zgodne z oczekiwaniami. (Oczywiście, jeśli spróbujesz powtórzyć ten przykład, twoje .tar i .tar.gz będą się różnić od tego, ze względu na różne znaczniki czasu)

Dowolna wskazówka dotycząca sposobu wykonania pracy byłaby bardzo doceniona, naprawdę wolałabym mieć go w jednym uruchomieniu (z TeeReaders).

Odpowiedz

5

Problem występuje, ponieważ tar nie czyta każdego bajtu od czytnika. Po spakowaniu każdego pliku należy opróżnić czytnik, aby każdy bajt był odczytywany i mieszany. Normalnie robię to używając io.Copy(), aby czytać do EOF.

package main 

import (
    "archive/tar" 
    "compress/gzip" 
    "crypto/md5" 
    "fmt" 
    "io" 
    "io/ioutil" 
    "os" 
) 

func main() { 
    tgz, _ := os.Open("tb.tar.gz") 
    gzMd5 := md5.New() 
    gz, _ := gzip.NewReader(io.TeeReader(tgz, gzMd5)) 
    tarMd5 := md5.New() 
    tee := io.TeeReader(gz, tarMd5) // need the reader later 
    tr := tar.NewReader(tee) 
    for { 
     fileMd5 := md5.New() 
     hdr, err := tr.Next() 
     if err == io.EOF { 
      break 
     } 
     io.Copy(fileMd5, tr) 
     fmt.Printf("%x %s\n", fileMd5.Sum(nil), hdr.Name) 
    } 
    io.Copy(ioutil.Discard, tee) // read unused portions of the tar file 
    fmt.Printf("%x tb.tar\n", tarMd5.Sum(nil)) 
    fmt.Printf("%x tb.tar.gz\n", gzMd5.Sum(nil)) 
} 

Inną opcją jest po prostu dodać io.Copy(tarMd5, gz) przed tarMd5.Sum() rozmowy. Myślę, że pierwszy sposób jest bardziej przejrzysty, nawet jeśli muszę dodać/zmodyfikować cztery linie zamiast jednej.