...

Source file src/pkg/cmd/go/internal/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	package dirhash
     7	
     8	import (
     9		"archive/zip"
    10		"crypto/sha256"
    11		"encoding/base64"
    12		"errors"
    13		"fmt"
    14		"io"
    15		"os"
    16		"path/filepath"
    17		"sort"
    18		"strings"
    19	)
    20	
    21	var DefaultHash = Hash1
    22	
    23	type Hash func(files []string, open func(string) (io.ReadCloser, error)) (string, error)
    24	
    25	func Hash1(files []string, open func(string) (io.ReadCloser, error)) (string, error) {
    26		h := sha256.New()
    27		files = append([]string(nil), files...)
    28		sort.Strings(files)
    29		for _, file := range files {
    30			if strings.Contains(file, "\n") {
    31				return "", errors.New("filenames with newlines are not supported")
    32			}
    33			r, err := open(file)
    34			if err != nil {
    35				return "", err
    36			}
    37			hf := sha256.New()
    38			_, err = io.Copy(hf, r)
    39			r.Close()
    40			if err != nil {
    41				return "", err
    42			}
    43			fmt.Fprintf(h, "%x  %s\n", hf.Sum(nil), file)
    44		}
    45		return "h1:" + base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
    46	}
    47	
    48	func HashDir(dir, prefix string, hash Hash) (string, error) {
    49		files, err := DirFiles(dir, prefix)
    50		if err != nil {
    51			return "", err
    52		}
    53		osOpen := func(name string) (io.ReadCloser, error) {
    54			return os.Open(filepath.Join(dir, strings.TrimPrefix(name, prefix)))
    55		}
    56		return hash(files, osOpen)
    57	}
    58	
    59	func DirFiles(dir, prefix string) ([]string, error) {
    60		var files []string
    61		dir = filepath.Clean(dir)
    62		err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error {
    63			if err != nil {
    64				return err
    65			}
    66			if info.IsDir() {
    67				return nil
    68			}
    69			rel := file
    70			if dir != "." {
    71				rel = file[len(dir)+1:]
    72			}
    73			f := filepath.Join(prefix, rel)
    74			files = append(files, filepath.ToSlash(f))
    75			return nil
    76		})
    77		if err != nil {
    78			return nil, err
    79		}
    80		return files, nil
    81	}
    82	
    83	func HashZip(zipfile string, hash Hash) (string, error) {
    84		z, err := zip.OpenReader(zipfile)
    85		if err != nil {
    86			return "", err
    87		}
    88		defer z.Close()
    89		var files []string
    90		zfiles := make(map[string]*zip.File)
    91		for _, file := range z.File {
    92			files = append(files, file.Name)
    93			zfiles[file.Name] = file
    94		}
    95		zipOpen := func(name string) (io.ReadCloser, error) {
    96			f := zfiles[name]
    97			if f == nil {
    98				return nil, fmt.Errorf("file %q not found in zip", name) // should never happen
    99			}
   100			return f.Open()
   101		}
   102		return hash(files, zipOpen)
   103	}
   104	

View as plain text