package main import ( "database/sql" _ "github.com/mattn/go-sqlite3" "log" "io" "fmt" "os" "crypto/sha1" "time" "path/filepath" "strconv" "encoding/hex" "encoding/binary" "hash" "reflect" ) const sampleSize = 16 * 1024 const sampleThreshold = 48 * 1024 func copyHash(src hash.Hash) hash.Hash { typ := reflect.TypeOf(src) val := reflect.ValueOf(src) if typ.Kind() == reflect.Ptr { typ = typ.Elem() val = val.Elem() } elem := reflect.New(typ).Elem() elem.Set(val) return elem.Addr().Interface().(hash.Hash) } func hash_directory (searchDir, database string) { db, dberr := sql.Open("sqlite3", database) if dberr != nil { log.Fatal(dberr) } defer db.Close() err := filepath.Walk(searchDir, func(path string, info os.FileInfo, err error) error { if err != nil { log.Fatal(err) return err } if !info.IsDir() { fmt.Printf("Name: %s\n", info.Name()) f, err := os.Open(path) if err != nil { log.Fatal(err) } defer f.Close() h := sha1.New() if _, err := io.Copy(h, f); err != nil { log.Fatal(err) } qh := copyHash(h) if info.Size() > int64(sampleThreshold) { qh.Reset() buffer := make([]byte, sampleSize) f.Read(buffer) qh.Write(buffer) f.Seek(info.Size()/2-sampleSize/2, 0) f.Read(buffer) qh.Write(buffer) f.Seek(int64(-sampleSize), 2) f.Read(buffer) qh.Write(buffer) } buffer := make([]byte, 8) binary.PutVarint(buffer, info.Size()) qh.Write(buffer) quickSum := hex.EncodeToString(qh.Sum(nil)) hashSum := hex.EncodeToString(h.Sum(nil)) fmt.Printf("SHA1: %x\n", hashSum) fmt.Printf("qSHA1: %x\n", quickSum) fmt.Printf("Size: %d\n", info.Size()) fmt.Printf("Time: %s\n\n", info.ModTime().Format(time.RFC3339)) sqlStatement := "INSERT INTO hashes (hash_sha1, filename, filesize_bytes, path, changedate )"+ "VALUES ('"+hashSum+"','"+info.Name()+"','"+strconv.FormatInt(info.Size(),10)+"','"+path+"','"+info.ModTime().Format(time.RFC3339)+"');" _, err = db.Exec(sqlStatement) if err != nil { log.Printf("%q: %s\n", err, sqlStatement) return nil } } return nil }) if err != nil { log.Fatal(err) } } func main() { dbname := "./sneakerhash.db" os.Remove(dbname) db, err := sql.Open("sqlite3", dbname) if err != nil { log.Fatal(err) } defer db.Close() sqlStatement := ` create table hashes ( hash_sha1 text not null primary key, filename text, filesize_bytes integer, path text, changedate datetime );` _, err = db.Exec(sqlStatement) if err != nil { log.Printf("%q: %s\n", err, sqlStatement) return } hash_directory(".", dbname) }