Reputation: 1275
I'm trying to calculate the sha1 hash of an uploaded file but so far I'm at a dead end. The sample code is as follows:
err := req.ParseMultipartForm(200000)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
m := req.MultipartForm
files := m.File["Filedata"]
for i, _ := range files {
file, err := files[i].Open()
defer file.Close()
fh = getFileHash(file)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
break
}
dst, err := os.Create(baseDir+fh+".jpg")
defer dst.Close()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
break
}
if _, err := io.Copy(dst, file); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
break
}
}
And the content of the getFileHash function is as follows:
func getFileHash (f *os.File) string {
fstat, err := f.Stat()
if err != nil {
panic(err)
}
fSize := fstat.Size()
buf := make([]byte, fSize)
hash := sha1.New()
n, err := f.Read(buf)
if _, err := io.WriteString(hash, string(buf[:n])); err != nil {
panic(err)
}
return string(hash.Sum(nil))
}
I'm getting the following error although I'm not sure how to get around this:
cannot use file (type multipart.File) as type *os.File in function argument: need type assertion
If I test by using a sample hash as the value of "fh", it works just fine.
I know I could simply save the file, calculate the hash, and then move the file although that's extra steps I'd rather not take if possible. I'd appreciate any help you could provide me with.
Thanks!
Upvotes: 2
Views: 2023
Reputation: 91030
You can stream the file to disk and a hash function at the same time. Here's a rough example:
Note: It does have one caveat: The error is not checked on the file being written. This can matter tremendously depending on your filesystem. You might consider something like errutil in production code.
package main
import (
"crypto/sha1"
"fmt"
"io"
"os"
"strings"
)
func shaAndSave(src io.Reader) ([]byte, error) {
h := sha1.New()
dest, err := os.Create("tmpfile.txt")
if err != nil {
return nil, err
}
defer dest.Close()
t := io.TeeReader(src, h)
_, err = io.Copy(dest, t)
if err != nil {
return nil, err
}
return h.Sum(nil), nil
}
func main() {
src := strings.NewReader("pretend this was a file")
hashBytes, err := shaAndSave(src)
fmt.Printf("Returned %x and %v", hashBytes, err)
}
Upvotes: 1
Reputation: 1683
From http://golang.org/pkg/mime/multipart/#File
File is an interface to access the file part of a multipart message. Its contents may be either stored in memory or on disk. If stored on disk, the File's underlying concrete type will be an *os.File.
So you are indeed not passing an *os.File type, since it is in memory. Try accepting multipart.File as a type.
Upvotes: 0