package main import ( "bufio" "crypto/md5" "errors" "fmt" "hash" "io" "os" "strings" "github.com/alexflint/go-arg" common "source.heropunch.io/tomo/go-coreutils" ) var ImproperlyFormattedErr = errors.New("improperly formatted line") func printSumForFile(filename string, sumFunc func(io.Reader) (hash.Hash, error)) error { file, err := os.Open(filename) if err != nil { return err } defer file.Close() h, err := sumFunc(file) if err != nil { return err } printHash(h, filename) return nil } func printSumForStdin(sumFunc func(io.Reader) (hash.Hash, error)) { h, err := sumFunc(os.Stdin) if err != nil { common.PrintToStderr(err) os.Exit(1) } printHash(h, "") os.Exit(0) } func md5sum(r io.Reader) (hash.Hash, error) { h := md5.New() if _, err := io.Copy(h, r); err != nil { return nil, err } return h, nil } func printHash(h hash.Hash, filename string) { fmt.Printf("%x %v\n", h.Sum(nil), filename) } func checkSumForFile(filename string) error { file, err := os.Open(filename) if err != nil { return err } defer file.Close() return checkSums(file) } func checkSums(r io.Reader) error { scanner := bufio.NewScanner(r) for scanner.Scan() { err := checkMD5Sum(scanner.Text()) if err != nil { return err } } return scanner.Err() } func checkMD5Sum(line string) error { s := strings.SplitN(line, " ", 2) hash := s[0] filename := s[1] if filename == "" { return ImproperlyFormattedErr } file, err := os.Open(filename) if err != nil { return err } defer file.Close() h, err := md5sum(file) if err != nil { return err } result := "OK" if fmt.Sprintf("%x", h.Sum(nil)) != hash { result = "FAILED" } fmt.Printf("%s: %s\n", filename, result) return nil } func main() { var args struct { Check bool `arg:"-c"` Files []string `arg:"positional"` } arg.MustParse(&args) exitCode := 0 if len(args.Files) == 0 { if !args.Check { printSumForStdin(md5sum) } else { fmt.Println("Checking from stdin") } } for _, filename := range args.Files { if !args.Check { err := printSumForFile(filename, md5sum) if err != nil { common.PrintToStderr(err) exitCode = 1 } } else { err := checkSumForFile(filename) if err != nil { common.PrintToStderr(err) exitCode = 1 } } } os.Exit(exitCode) }