/*
GoCheese -- Python private package repository and caching proxy
-Copyright (C) 2019-2021 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2019-2023 Sergey Matveev <stargrave@stargrave.org>
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
"bufio"
"bytes"
"crypto/sha256"
+ "errors"
"fmt"
- "hash"
"io"
- "io/ioutil"
+ "io/fs"
"log"
"os"
"path/filepath"
+ "runtime"
"strings"
-
- "golang.org/x/crypto/blake2b"
+ "sync"
)
-func checkFile(
- pkgName, fn, fnHash, hasherName string,
- hasher hash.Hash, digest []byte,
-) bool {
- expected, err := ioutil.ReadFile(fnHash)
- if err != nil {
- log.Fatal(err)
- }
- fd, err := os.Open(fn)
- if err != nil {
- if os.IsNotExist(err) {
- return true
+func checker(jobs chan string, isGood *bool, workers *sync.WaitGroup) {
+ hasherBLAKE2b256 := blake2b256New()
+ hasherSHA256 := sha256.New()
+ digestBuf := make([]byte, 32)
+ defer workers.Done()
+ var fd *os.File
+ var br bufio.Reader
+ var err error
+ var digest []byte
+ for fn := range jobs {
+ fd, err = os.Open(fn)
+ if err != nil {
+ fmt.Println("ERR", fn, err)
+ *isGood = false
+ continue
+ }
+
+ digest, err = os.ReadFile(fn + "." + HashAlgoBLAKE2b256)
+ if err != nil {
+ if !errors.Is(err, fs.ErrNotExist) {
+ fmt.Println("ERR", fn+"."+HashAlgoBLAKE2b256, err)
+ *isGood = false
+ }
+ goto NoBLAKE2b256
+ }
+ hasherBLAKE2b256.Reset()
+ br.Reset(fd)
+ _, err = io.Copy(hasherBLAKE2b256, &br)
+ fd.Seek(0, io.SeekStart)
+ if err != nil {
+ fmt.Println("ERR", fn+"."+HashAlgoBLAKE2b256, err)
+ *isGood = false
+ goto NoBLAKE2b256
+ }
+ if bytes.Equal(hasherBLAKE2b256.Sum(digestBuf[:0]), digest) {
+ fmt.Println("GOOD", fn+"."+HashAlgoBLAKE2b256)
+ } else {
+ fmt.Println("BAD", fn+"."+HashAlgoBLAKE2b256)
+ *isGood = false
+ }
+
+ NoBLAKE2b256:
+ digest, err = os.ReadFile(fn + "." + HashAlgoSHA256)
+ if err != nil {
+ if !errors.Is(err, fs.ErrNotExist) {
+ fmt.Println("ERR", fn+"."+HashAlgoSHA256, err)
+ *isGood = false
+ }
+ fd.Close()
+ continue
+ }
+ hasherSHA256.Reset()
+ br.Reset(fd)
+ _, err = io.Copy(hasherSHA256, &br)
+ fd.Close()
+ if err != nil {
+ fmt.Println("ERR", fn+"."+HashAlgoBLAKE2b256, err)
+ *isGood = false
+ continue
+ }
+ if bytes.Equal(hasherSHA256.Sum(digestBuf[:0]), digest) {
+ fmt.Println("GOOD", fn+"."+HashAlgoSHA256)
+ } else {
+ fmt.Println("BAD", fn+"."+HashAlgoSHA256)
+ *isGood = false
}
- log.Fatal(err)
- }
- _, err = io.Copy(hasher, bufio.NewReader(fd))
- fd.Close()
- if err != nil {
- log.Fatal(err)
- }
- isEqual := bytes.Compare(hasher.Sum(digest[:0]), expected) == 0
- hasher.Reset()
- if isEqual {
- fmt.Println("GOOD", hasherName, pkgName)
- return true
}
- fmt.Println("BAD", hasherName, pkgName)
- return false
}
func goodIntegrity() bool {
- dirs, err := ioutil.ReadDir(*Root)
+ isGood := true
+ jobs := make(chan string, 1<<10)
+ var workers sync.WaitGroup
+ workers.Add(runtime.NumCPU())
+ for i := 0; i < runtime.NumCPU(); i++ {
+ go checker(jobs, &isGood, &workers)
+ }
+ fd, err := os.Open(Root)
+ if err != nil {
+ log.Fatal(err)
+ }
+ dirs, err := fd.ReadDir(0)
+ fd.Close()
if err != nil {
log.Fatal(err)
}
- hasherSHA256 := sha256.New()
- hasherBLAKE2b256 := blake2b256New()
- digestSHA256 := make([]byte, sha256.Size)
- digestBLAKE2b256 := make([]byte, blake2b.Size256)
- isGood := true
- var pkgName string
for _, dir := range dirs {
- files, err := ioutil.ReadDir(filepath.Join(*Root, dir.Name()))
+ fd, err = os.Open(filepath.Join(Root, dir.Name()))
+ if err != nil {
+ log.Fatal(err)
+ }
+ files, err := fd.ReadDir(0)
+ fd.Close()
if err != nil {
log.Fatal(err)
}
for _, file := range files {
- if strings.HasSuffix(file.Name(), "."+HashAlgoSHA256) {
- pkgName = strings.TrimSuffix(file.Name(), "."+HashAlgoSHA256)
- if !checkFile(
- pkgName,
- filepath.Join(*Root, dir.Name(), pkgName),
- filepath.Join(*Root, dir.Name(), file.Name()),
- "SHA256", hasherSHA256, digestSHA256,
- ) {
- isGood = false
- }
- continue
- }
- if strings.HasSuffix(file.Name(), "."+HashAlgoBLAKE2b256) {
- pkgName = strings.TrimSuffix(file.Name(), "."+HashAlgoBLAKE2b256)
- if !checkFile(
- pkgName,
- filepath.Join(*Root, dir.Name(), pkgName),
- filepath.Join(*Root, dir.Name(), file.Name()),
- "BLAKE2b-256", hasherBLAKE2b256, digestBLAKE2b256,
- ) {
- isGood = false
+ for _, ext := range KnownExts {
+ if strings.HasSuffix(file.Name(), ext) {
+ jobs <- filepath.Join(Root, dir.Name(), file.Name())
}
}
}
}
+ close(jobs)
+ workers.Wait()
return isGood
}