2013-03-02 19 views
5

Tôi vừa thử nghiệm lưu trữ/tar và nén/gzip, để xử lý tự động một số bản sao lưu mà tôi có.Tại sao băm md5 của tar-part của tar.gz thông qua TeeReader sai?

Vấn đề của tôi là: Tôi có nhiều tệp .tar và tệp .tar.gz khác nhau, và do đó tôi muốn trích xuất hàm băm (md5) của tệp .tar.gz và hàm băm (md5) của các tập tin .tar là tốt, lý tưởng trong một lần chạy.

Mã ví dụ tôi có cho đến nay, hoạt động hoàn toàn tốt cho các băm của tệp trong .tar.gz cũng như .gz, nhưng băm cho .tar là sai và tôi không thể tìm ra vấn đề là gì.

Tôi đã xem tệp tar/reader.go và thấy rằng có một số bỏ qua trong đó, nhưng tôi nghĩ mọi thứ sẽ chạy trên giao diện io.Reader và do đó TeeReader vẫn nên nắm bắt tất cả các byte.

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)) 
} 

Bây giờ cho các ví dụ sau:

$ 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 

Trên Linux Mint 14 (dựa trên Ubuntu 12.04) với đi 1,02 từ Ubuntu kho lưu trữ kết quả cho chương trình đi của tôi là:

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

Vì vậy, tất cả các băm ngoại trừ tb.tar đều như mong đợi. (Tất nhiên nếu bạn thử lại ví dụ đó .tar và .tar.gz của bạn sẽ khác với điều này, vì các dấu thời gian khác nhau)

Bất kỳ gợi ý nào về cách làm việc đó sẽ được đánh giá cao, tôi thực sự muốn có nó trong 1 chạy mặc dù (với TeeReaders).

Trả lời

5

Sự cố xảy ra vì tar không đọc từng byte từ trình đọc của bạn. Sau khi băm nhỏ từng tập tin, bạn cần làm trống đầu đọc để đảm bảo mỗi byte được đọc và băm. Cách tôi thường làm điều này là sử dụng io.Copy() để đọc cho đến 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)) 
} 

Một tùy chọn khác là chỉ cần thêm io.Copy(tarMd5, gz) trước lệnh tarMd5.Sum() của bạn. Tôi nghĩ rằng cách đầu tiên là rõ ràng hơn ngay cả khi tôi cần phải thêm/sửa đổi bốn dòng thay vì một.