2013-03-02 1 views
5

J'étais en train d'expérimenter avec archive/tar et compress/gzip, pour le traitement automatisé de certaines sauvegardes que j'ai. Mon problème ici est: J'ai divers fichiers .tar et fichiers .tar.gz flottant autour, et donc je veux extraire le hachage (md5) du fichier .tar.gz, et le hachage (MD5) de le fichier .tar aussi, idéalement en un seul passage.Pourquoi le hachage md5 de la partie tar d'un tar.gz via TeeReader est-il incorrect?

L'exemple de code que j'ai jusqu'ici, fonctionne parfaitement bien pour les hachages des fichiers dans le .tar.gz aussi bien pour le .gz, mais le hachage pour le .tar est faux et je ne peux pas savoir quel est le problème. J'ai regardé le fichier tar/reader.go et j'ai vu qu'il y avait quelques sauts dedans, mais je pensais que tout devrait tourner sur l'interface io.Reader et donc le TeeReader devrait quand même attraper tous les octets.

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

Maintenant, pour l'exemple suivant:

$ 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 

Sur Linux Mint 14 (basé sur Ubuntu 12.04) avec aller 1.02 depuis les dépôts Ubuntu le résultat de mon programme de go est:

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

Donc, tous les hachages sauf tb.tar sont comme prévu. (Bien sûr si vous réessayez cet exemple votre .tar et .tar.gz sera différent de cela, en raison de timestamps différents)

Tout indice sur la façon de le faire fonctionner serait grandement apprécié, je préférerais vraiment l'avoir en 1 course bien (avec les TeeReaders).

Répondre

5

Le problème se produit car tar ne lit pas tous les octets de votre lecteur. Après avoir haché chaque fichier, vous devez vider le lecteur pour vous assurer que tous les octets sont lus et hachés. La façon dont je le fais normalement est d'utiliser io.Copy() pour lire jusqu'à 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)) 
} 

Une autre option consiste à ajouter juste io.Copy(tarMd5, gz) avant votre appel tarMd5.Sum(). Je pense que la première façon est plus claire même si j'avais besoin d'ajouter/modifier quatre lignes au lieu d'une seule.

Questions connexes