Skip to content

Commit

Permalink
Add code
Browse files Browse the repository at this point in the history
  • Loading branch information
matrixik committed Jun 17, 2020
1 parent d597967 commit 2eb5bf4
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 1 deletion.
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,43 @@
# hashdir
Generate hash for folder structure

Generate hash of all files and they paths for specified directory.

```go
package main

import (
"fmt"

"github.com/gosimple/hashdir"
)

func main() {
dirHash, err := hashdir.Make("./someDir/", "md5")
fmt.Println(dirHash)
}
```

Supported hashes:

* md5
* sha1
* sha256
* sha512

### Requests or bugs?

<https://github.com/gosimple/hashdir/issues>

## Installation

```sh
go get -u github.com/gosimple/hashdir
```

## License

The source files are distributed under the
[Mozilla Public License, version 2.0](http://mozilla.org/MPL/2.0/),
unless otherwise noted.
Please read the [FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html)
if you have further questions regarding the license.
1 change: 1 addition & 0 deletions assets/one_more/testowe3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
My insides are ready to check ;)
1 change: 1 addition & 0 deletions assets/testowe.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
check me
1 change: 1 addition & 0 deletions assets/testowe2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Don't forget about checking me :(
29 changes: 29 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2020 by Dobrosław Żybort. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/*
Package hashdir generate hash of all files and they paths for specified
directory.
Example:
package main
import (
"fmt"
"github.com/gosimple/hashdir"
)
func main() {
dirHash, err := hashdir.Make("./someDir/", "md5")
fmt.Println(dirHash)
}
Requests or bugs?
https://github.com/gosimple/hashdir/issues
*/
package hashdir
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.org/gosimple/hashdir

go 1.14
123 changes: 123 additions & 0 deletions hashdir.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package hashdir

import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"errors"
"hash"
"io"
"os"
"path/filepath"
"strings"
)

// Make generate hash of all files and they paths for specified directory.
func Make(dir string, hashType string) (string, error) {
var endHash string

bigErr := filepath.Walk(dir,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

endHash, err = hashData(endHash, hashType)
if err != nil {
return err
}

if !info.IsDir() {
pathHash, err := hashData(path, hashType)
if err != nil {
return err
}
fileHash, err := hashFile(path, hashType)
if err != nil {
return err
}
// log.Println(path, fileHash, info.ModTime())
endHash = endHash + pathHash + fileHash
}
return nil
})

if bigErr != nil {
return "", bigErr
}
endHash, err := hashData(endHash, hashType)
if err != nil {
return "", err
}
return endHash, err
}

func selectHash(hashType string) (hash.Hash, error) {
switch strings.ToLower(hashType) {
case "md5":
return md5.New(), nil
case "sha1":
return sha1.New(), nil
case "sha256":
return sha256.New(), nil
case "sha512":
return sha512.New(), nil
}
return nil, errors.New("Unknown hash: " + hashType)
}

func hashData(data string, hashType string) (string, error) {
h, err := selectHash(hashType)
if err != nil {
return "", err
}

_, err = h.Write([]byte(data))
if err != nil {
return "", err
}
return hex.EncodeToString(h.Sum(nil)), nil
}

func hashFile(path string, hashType string) (string, error) {
// Handle hashing big files.
// Source: https://stackoverflow.com/q/60328216/1722542

f, err := os.Open(path)
if err != nil {
return "", err
}

defer func() {
_ = f.Close()
}()

buf := make([]byte, 1024*1024)
h, err := selectHash(hashType)
if err != nil {
return "", err
}

for {
bytesRead, err := f.Read(buf)
if err != nil {
if err != io.EOF {
return "", err
}
_, err = h.Write(buf[:bytesRead])
if err != nil {
return "", err
}
break
}
_, err = h.Write(buf[:bytesRead])
if err != nil {
return "", err
}
}

fileHash := hex.EncodeToString(h.Sum(nil))
return fileHash, nil
}
83 changes: 83 additions & 0 deletions hashdir_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package hashdir

import "testing"

func TestMake(t *testing.T) {
type args struct {
root string
hashType string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
"Test making MD5 hash",
args{
"./assets/",
"md5",
},
"2d03afa7a1d8e7de98ce8a56660f86ff",
false,
},
{
"Test making SHA1 hash",
args{
"./assets/",
"SHA1",
},
"6049fcf8e09f83a28d769f8493b2af35a0824886",
false,
},
{
"Test making SHA256 hash",
args{
"./assets/",
"sha256",
},
"a7da71b33ec7ce8179b6d47cab465e0b51e581de8086c9e3d7f4e71ee36a39fd",
false,
},
{
"Test making SHA512 hash",
args{
"./assets/",
"SHA512",
},
"5427e699678230eb1a813691d1e7925e5549ad1541bf3e380e7a8267d13fad331873ccb90ebba10f54713653b0fdd82d14532ff956e17519e557790e8c477dcf",
false,
},
{
"Test making with wrong hash name",
args{
"./assets/",
"unknownHash",
},
"",
true,
},
{
"Test non existing folder",
args{
"./someDir/",
"md5",
},
"",
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Make(tt.args.root, tt.args.hashType)
if (err != nil) != tt.wantErr {
t.Errorf("Make() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Make() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 2eb5bf4

Please sign in to comment.