README | 2 +- cmd/meta4ra/check.go | 40 ++++++++++++++++++++++++++++++++++------ internal/common.go | 2 +- diff --git a/README b/README index 39fcbff4e733e17cc5cc902f244a5b01023b8b56f153efb52e9d1f25a219ac87..82e5809f8d2f5493820199c15e970bd5cf8e6197bac9e00111c7d4bb02784e3c 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ (https://datatracker.ietf.org/doc/html/rfc5854) .meta4-file for single specified file. meta4ra-check utility is used to check .meta4 file, extract signatures -and verify corresponding files integrity. +and verify corresponding files integrity. Optionally download files. meta4ra-hash utility can be used to hash the data with a single hash algorithm. It could be useful if you want to use the best found diff --git a/cmd/meta4ra/check.go b/cmd/meta4ra/check.go index 64693b9ebd2e6e14a1350ee0c0a968e5bc035ba9403206f9eefe667c58936c99..6d1b11b2d62d31e9cce4fcf3098d615fa79c426b899b8152507f8f24d44b3c08 100644 --- a/cmd/meta4ra/check.go +++ b/cmd/meta4ra/check.go @@ -23,6 +23,7 @@ "fmt" "io" "io/fs" "log" + "net/http" "os" "path" "strings" @@ -37,6 +38,7 @@ 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") + dl := flag.Int("dl", -1, "URL index to download, instead of reading from stdin") flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] [FILE ...]\n", os.Args[0]) @@ -46,6 +48,10 @@ If no FILEs are specified, then all s from metalink are searched and verified if they exist. Otherwise only specified FILEs are checked. If you want to skip any verification (for example only to validate the format and -extract-sig, then you can just specify an empty ("") FILE. + +If -dl (> 0) is specified, then it automatically implies -pipe, but +downloads data by specified URLs index, instead of reading from stdin. +That can be used as a downloading utility. `) } flag.Parse() @@ -72,6 +78,9 @@ toCheck := make(map[string]string) for _, fn := range flag.Args() { toCheck[path.Base(fn)] = fn + } + if *dl != -1 { + *pipe = true } if *pipe && len(toCheck) != 1 { log.Fatalln("exactly single FILE must be specified when using -pipe") @@ -155,19 +164,38 @@ bad = true continue HashFound: - fd := os.Stdin + var src io.ReadCloser + src = os.Stdin if !*pipe { - fd, err = os.Open(fullPath) + src, err = os.Open(fullPath) if err != nil { log.Println("Error:", f.Name, err) bad = true continue } } + if *dl != -1 { + resp, err := http.Get(f.URLs[*dl].URL) + if err != nil { + log.Println("Error:", f.Name, err) + bad = true + continue + } + log.Println("HTTP response:") + for k := range resp.Header { + log.Println("\t"+k+":", resp.Header.Get(k)) + } + if resp.StatusCode != http.StatusOK { + log.Println("Bad status code:", f.Name, resp.Status) + bad = true + continue + } + src = resp.Body + } err = hasher.Start() if err != nil { if !*pipe { - fd.Close() + src.Close() } hasher.Stop() log.Println("Error:", f.Name, err) @@ -180,9 +208,9 @@ w = io.MultiWriter(os.Stdout, hasher) } else { w = hasher } - _, err = io.Copy(w, bufio.NewReaderSize(fd, meta4ra.BufLen)) - if !*pipe { - fd.Close() + _, err = io.Copy(w, bufio.NewReaderSize(src, meta4ra.BufLen)) + if !*pipe || *dl != -1 { + src.Close() } if err != nil { hasher.Stop() diff --git a/internal/common.go b/internal/common.go index 84495998ee17d4a0520bd8e28fb03e59d06aebe4faa390caeb18895b67e63e1e..184ebc8c2c0bb2284fc44079bc278df3d33a5857e9f01061f23ceb4bc2400e9f 100644 --- a/internal/common.go +++ b/internal/common.go @@ -21,7 +21,7 @@ "runtime" ) const ( - Generator = "meta4ra/0.8.0" + Generator = "meta4ra/0.9.0" SigMediaTypePGP = "application/pgp-signature" SigMediaTypeSSH = "application/ssh-signature" BufLen = 1 << 20