2 meta4a -- Metalink 4.0 checker
3 Copyright (C) 2021-2022 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // Metalink 4.0 checker
35 "go.stargrave.org/meta4ra"
39 extractSig := flag.Bool("extract-sig", false, "Extract signature files")
40 log.SetFlags(log.Lshortfile)
42 sha256Hasher := sha256.New()
43 sha512Hasher := sha512.New()
45 for _, metaPath := range flag.Args() {
46 data, err := os.ReadFile(metaPath)
50 var meta meta4ra.Metalink
51 err = xml.Unmarshal(data, &meta)
55 for _, f := range meta.Files {
56 if f.Signature != nil && *extractSig {
57 if err = os.WriteFile(
59 []byte(f.Signature.Signature),
62 fmt.Println("Error:", f.Name, "can not save signature:", err)
66 var sha256Digest string
67 var sha512Digest string
68 fd, err := os.Open(f.Name)
72 for _, h := range f.Hashes {
74 case meta4ra.HashSHA256:
76 case meta4ra.HashSHA512:
80 var digestTheir string
83 if sha512Digest != "" {
84 digestName = meta4ra.HashSHA512
85 digestTheir = sha512Digest
87 } else if sha256Digest != "" {
88 digestName = meta4ra.HashSHA256
89 digestTheir = sha256Digest
93 fmt.Println("Error:", f.Name, "no satisfiable hash algorithm found")
98 _, err = io.Copy(hasher, bufio.NewReader(fd))
101 fmt.Println("Error:", f.Name, err)
105 digestOur := hex.EncodeToString(hasher.Sum(nil))
106 if digestOur == digestTheir {
107 fmt.Println(f.Name, digestName, "good")
110 "Hash does not match:", f.Name, digestName,
112 "their:", digestTheir,