]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/golang.org/x/mod/sumdb/dirhash/hash.go
Add error check on return value of build_co_await
[thirdparty/gcc.git] / libgo / go / golang.org / x / mod / sumdb / dirhash / hash.go
1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package dirhash defines hashes over directory trees.
6 // These hashes are recorded in go.sum files and in the Go checksum database,
7 // to allow verifying that a newly-downloaded module has the expected content.
8 package dirhash
9
10 import (
11 "archive/zip"
12 "crypto/sha256"
13 "encoding/base64"
14 "errors"
15 "fmt"
16 "io"
17 "os"
18 "path/filepath"
19 "sort"
20 "strings"
21 )
22
23 // DefaultHash is the default hash function used in new go.sum entries.
24 var DefaultHash Hash = Hash1
25
26 // A Hash is a directory hash function.
27 // It accepts a list of files along with a function that opens the content of each file.
28 // It opens, reads, hashes, and closes each file and returns the overall directory hash.
29 type Hash func(files []string, open func(string) (io.ReadCloser, error)) (string, error)
30
31 // Hash1 is the "h1:" directory hash function, using SHA-256.
32 //
33 // Hash1 is "h1:" followed by the base64-encoded SHA-256 hash of a summary
34 // prepared as if by the Unix command:
35 //
36 // find . -type f | sort | sha256sum
37 //
38 // More precisely, the hashed summary contains a single line for each file in the list,
39 // ordered by sort.Strings applied to the file names, where each line consists of
40 // the hexadecimal SHA-256 hash of the file content,
41 // two spaces (U+0020), the file name, and a newline (U+000A).
42 //
43 // File names with newlines (U+000A) are disallowed.
44 func Hash1(files []string, open func(string) (io.ReadCloser, error)) (string, error) {
45 h := sha256.New()
46 files = append([]string(nil), files...)
47 sort.Strings(files)
48 for _, file := range files {
49 if strings.Contains(file, "\n") {
50 return "", errors.New("dirhash: filenames with newlines are not supported")
51 }
52 r, err := open(file)
53 if err != nil {
54 return "", err
55 }
56 hf := sha256.New()
57 _, err = io.Copy(hf, r)
58 r.Close()
59 if err != nil {
60 return "", err
61 }
62 fmt.Fprintf(h, "%x %s\n", hf.Sum(nil), file)
63 }
64 return "h1:" + base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
65 }
66
67 // HashDir returns the hash of the local file system directory dir,
68 // replacing the directory name itself with prefix in the file names
69 // used in the hash function.
70 func HashDir(dir, prefix string, hash Hash) (string, error) {
71 files, err := DirFiles(dir, prefix)
72 if err != nil {
73 return "", err
74 }
75 osOpen := func(name string) (io.ReadCloser, error) {
76 return os.Open(filepath.Join(dir, strings.TrimPrefix(name, prefix)))
77 }
78 return hash(files, osOpen)
79 }
80
81 // DirFiles returns the list of files in the tree rooted at dir,
82 // replacing the directory name dir with prefix in each name.
83 // The resulting names always use forward slashes.
84 func DirFiles(dir, prefix string) ([]string, error) {
85 var files []string
86 dir = filepath.Clean(dir)
87 err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error {
88 if err != nil {
89 return err
90 }
91 if info.IsDir() {
92 return nil
93 }
94 rel := file
95 if dir != "." {
96 rel = file[len(dir)+1:]
97 }
98 f := filepath.Join(prefix, rel)
99 files = append(files, filepath.ToSlash(f))
100 return nil
101 })
102 if err != nil {
103 return nil, err
104 }
105 return files, nil
106 }
107
108 // HashZip returns the hash of the file content in the named zip file.
109 // Only the file names and their contents are included in the hash:
110 // the exact zip file format encoding, compression method,
111 // per-file modification times, and other metadata are ignored.
112 func HashZip(zipfile string, hash Hash) (string, error) {
113 z, err := zip.OpenReader(zipfile)
114 if err != nil {
115 return "", err
116 }
117 defer z.Close()
118 var files []string
119 zfiles := make(map[string]*zip.File)
120 for _, file := range z.File {
121 files = append(files, file.Name)
122 zfiles[file.Name] = file
123 }
124 zipOpen := func(name string) (io.ReadCloser, error) {
125 f := zfiles[name]
126 if f == nil {
127 return nil, fmt.Errorf("file %q not found in zip", name) // should never happen
128 }
129 return f.Open()
130 }
131 return hash(files, zipOpen)
132 }