/* meta4a -- Metalink 4.0 checker Copyright (C) 2021-2023 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ // Metalink 4.0 checker package main import ( "bufio" "encoding/xml" "flag" "fmt" "io" "io/fs" "log" "os" "strings" "go.stargrave.org/meta4ra" ) func main() { hashes := flag.String("hashes", strings.Join(meta4ra.HashesDefault, ","), "hash-name:command-s") extractSig := flag.Bool("extract-sig", false, "Extract signature files") log.SetFlags(log.Lshortfile) flag.Parse() bad := false for _, metaPath := range flag.Args() { data, err := os.ReadFile(metaPath) if err != nil { log.Fatalln(err) } var meta meta4ra.Metalink err = xml.Unmarshal(data, &meta) if err != nil { log.Fatalln(err) } for _, f := range meta.Files { if f.Signature != nil && *extractSig { if err = os.WriteFile( f.Name+".asc", []byte(f.Signature.Signature), fs.FileMode(0666), ); err != nil { fmt.Println("Error:", f.Name, "can not save signature:", err) bad = true } } hasher := meta4ra.NewHasher(*hashes) var hashTheir string var hashName string for i, name := range hasher.Names { for _, h := range f.Hashes { if h.Type == name { hasher.Names = []string{name} hasher.Cmds = append(hasher.Cmds[:0], hasher.Cmds[i]) hasher.Ins = append(hasher.Ins[:0], hasher.Ins[i]) hasher.Outs = append(hasher.Outs[:0], hasher.Outs[i]) hashName = name hashTheir = h.Hash goto HashFound } } } log.Fatalln("no common hashes found for:", f.Name) HashFound: fd, err := os.Open(f.Name) if err != nil { continue } hasher.Start() _, err = io.Copy(hasher, bufio.NewReaderSize(fd, 1<<20)) fd.Close() sums := hasher.Sums() if err != nil { fmt.Println("Error:", f.Name, err) bad = true continue } hashOur := sums[0].Hash if hashOur == hashTheir { fmt.Println(f.Name, hashName, "good") } else { fmt.Println( "Hash does not match:", f.Name, hashName, "our:", hashOur, "their:", hashTheir, ) bad = true continue } } } if bad { os.Exit(1) } }