X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=integrity.go;h=f01d7a740fc8c40ee3b386df0b4e26b0f11ea88a;hb=2899b3bc394a1df21a20e4cbfc6650ee7dac9106;hp=1e0dddde15c86657d48e26d5f3e9aa928765b851;hpb=60834a0713d5dcc6a9911511cb8618ce7358c824;p=gocheese.git diff --git a/integrity.go b/integrity.go index 1e0dddd..f01d7a7 100644 --- a/integrity.go +++ b/integrity.go @@ -1,73 +1,141 @@ -/* -GoCheese -- Python private package repository and caching proxy -Copyright (C) 2019-2021 Sergey Matveev - -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 -the Free Software Foundation, version 3 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ +// GoCheese -- Python private package repository and caching proxy +// Copyright (C) 2019-2024 Sergey Matveev +// +// 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 +// the Free Software Foundation, version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . package main import ( + "bufio" "bytes" "crypto/sha256" + "errors" "fmt" - "io/ioutil" + "io" + "io/fs" "log" "os" "path/filepath" + "runtime" "strings" + "sync" ) +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 + } + } +} + 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) } - hasher := sha256.New() - digest := make([]byte, sha256.Size) - isGood := true - var data []byte - 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) { - continue - } - pkgName = strings.TrimSuffix(file.Name(), "."+HashAlgoSHA256) - data, err = ioutil.ReadFile(filepath.Join(*Root, dir.Name(), pkgName)) - if err != nil { - if os.IsNotExist(err) { - continue + for _, ext := range KnownExts { + if strings.HasSuffix(file.Name(), ext) { + jobs <- filepath.Join(Root, dir.Name(), file.Name()) } - log.Fatal(err) - } - hasher.Write(data) - data, err = ioutil.ReadFile(filepath.Join(*Root, dir.Name(), file.Name())) - if err != nil { - log.Fatal(err) - } - if bytes.Compare(hasher.Sum(digest[:0]), data) == 0 { - fmt.Println("GOOD", pkgName) - } else { - isGood = false - fmt.Println("BAD", pkgName) } - hasher.Reset() } } + close(jobs) + workers.Wait() return isGood }