// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-// Metalink 4.0 checker
package main
import (
"path"
"strings"
- "go.stargrave.org/meta4ra"
+ meta4ra "go.stargrave.org/meta4ra/internal"
)
-func main() {
- hashes := flag.String("hashes",
- strings.Join(meta4ra.HashesDefault, ","), "hash-name:command-s")
+func runCheck() {
+ stdin := flag.Bool("stdin", false, "Compare data of single file taken from stdin")
+ allHashes := flag.Bool("all-hashes", false, "Check all hashes, not the first common one")
+ hashes := flag.String("hashes", meta4ra.HashesDefault,
+ "hash-name:commandline[,...]")
extractSig := flag.Bool("extract-sig", false, "Extract signature files")
metaPath := flag.String("meta4", "file.meta4", "Metalink file")
flag.Usage = func() {
If no FILEs are specified, then all <file>s from metalink are searched and
verified if they exist. Otherwise only specified FILEs are checked. If you
want to skip any <file> verification (for example only to validate the format
-and -extract-sig, then you can just specify empty ("") FILE.
+and -extract-sig, then you can just specify an empty ("") FILE.
`)
}
flag.Parse()
- log.SetFlags(log.Lshortfile)
data, err := os.ReadFile(*metaPath)
if err != nil {
for _, fn := range flag.Args() {
toCheck[path.Base(fn)] = fn
}
+ if *stdin && len(toCheck) != 1 {
+ log.Fatalln("exactly single FILE must be specified when using -stdin")
+ }
bad := false
for _, f := range meta.Files {
}
fullPath := toCheck[f.Name]
+ delete(toCheck, f.Name)
if !(len(toCheck) == 0 || fullPath != "") {
continue
}
if fullPath == "" {
fullPath = f.Name
}
- s, err := os.Stat(fullPath)
- if err != nil {
- fmt.Println(err)
- bad = true
- continue
+ if !*stdin {
+ s, err := os.Stat(fullPath)
+ if err != nil {
+ fmt.Println(err)
+ bad = true
+ continue
+ }
+ if uint64(s.Size()) != f.Size {
+ fmt.Println("size mismatch",
+ f.Name, "our:", s.Size(), "their:", f.Size)
+ bad = true
+ continue
+ }
}
- if uint64(s.Size()) != f.Size {
- fmt.Println("size mismatch",
- f.Name, "our:", s.Size(), "their:", f.Size)
+
+ hasher, err := meta4ra.NewHasher(*hashes)
+ if err != nil {
+ fmt.Println(f.Name, err)
bad = true
continue
}
-
- hasher := meta4ra.NewHasher(*hashes)
var hashTheir string
var hashName string
+ if *allHashes {
+ goto HashFound
+ }
for i, name := range hasher.Names {
for _, h := range f.Hashes {
if h.Type == name {
fmt.Println("no common hashes found for:", f.Name)
bad = true
continue
-
HashFound:
- fd, err := os.Open(fullPath)
+
+ fd := os.Stdin
+ if !*stdin {
+ fd, err = os.Open(fullPath)
+ if err != nil {
+ fmt.Println("Error:", f.Name, err)
+ bad = true
+ continue
+ }
+ }
+ err = hasher.Start()
if err != nil {
+ if !*stdin {
+ fd.Close()
+ }
+ hasher.Stop()
fmt.Println("Error:", f.Name, err)
bad = true
continue
}
- hasher.Start()
- _, err = io.Copy(hasher, bufio.NewReaderSize(fd, 1<<20))
- fd.Close()
- sums := hasher.Sums()
+ _, err = io.Copy(hasher, bufio.NewReaderSize(fd, meta4ra.BufLen))
+ if !*stdin {
+ fd.Close()
+ }
if err != nil {
+ hasher.Stop()
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 mismatch:", f.Name, hashName,
- "our:", hashOur,
- "their:", hashTheir,
- )
+ sums, err := hasher.Sums()
+ if err != nil {
+ hasher.Stop()
+ fmt.Println("Error:", f.Name, err)
bad = true
continue
}
+ if *allHashes {
+ hashesOur := make(map[string]string, len(sums))
+ for _, h := range sums {
+ hashesOur[h.Type] = h.Hash
+ }
+ for _, h := range f.Hashes {
+ hashOur := hashesOur[h.Type]
+ if h.Hash == hashOur {
+ fmt.Println(f.Name, h.Type, "good")
+ } else {
+ fmt.Println(
+ "hash mismatch:", f.Name, h.Type,
+ "our:", hashOur,
+ "their:", h.Hash,
+ )
+ bad = true
+ }
+ }
+ } else {
+ hashOur := sums[0].Hash
+ if hashOur == hashTheir {
+ fmt.Println(f.Name, hashName, "good")
+ } else {
+ fmt.Println(
+ "hash mismatch:", f.Name, hashName,
+ "our:", hashOur,
+ "their:", hashTheir,
+ )
+ bad = true
+ continue
+ }
+ }
+ }
+ if len(toCheck) != 0 {
+ fmt.Println("not all FILEs met")
+ bad = true
}
if bad {
os.Exit(1)