...

Source file src/github.com/rogpeppe/go-internal/dirhash/hash.go

Documentation: github.com/rogpeppe/go-internal/dirhash

     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