git-lfs/pointer/writer.go
2014-07-28 17:38:09 -06:00

71 lines
1.4 KiB
Go

package pointer
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"hash"
"io"
"io/ioutil"
"os"
)
// consistentFileWriter ensures that the file matching the given SHA-256
// signature is written to the given path.
type consistentFileWriter struct {
Path string
Sha256 string
writer io.Writer
file *os.File
tmpFile *os.File
hasher hash.Hash
}
func newFile(path, sha256Sig string) (*consistentFileWriter, error) {
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0660)
if err != nil {
return nil, err
}
tmpFile, err := ioutil.TempFile("", sha256Sig)
if err != nil {
return nil, err
}
h := sha256.New()
w := io.MultiWriter(tmpFile, h)
return &consistentFileWriter{path, sha256Sig, w, file, tmpFile, h}, nil
}
func (w *consistentFileWriter) Write(p []byte) (int, error) {
return w.writer.Write(p)
}
func (w *consistentFileWriter) Close() error {
defer func() {
w.file.Close()
w.tmpFile.Close()
os.RemoveAll(w.tmpFile.Name())
}()
writtenSha := hex.EncodeToString(w.hasher.Sum(nil))
if writtenSha != w.Sha256 {
return fmt.Errorf("Unexpected SHA-256 trying to write %s. Expected %s, got %s.", w.Path, w.Sha256, writtenSha)
}
offset, err := w.tmpFile.Seek(0, 0)
if err != nil {
return err
}
if offset != 0 {
return fmt.Errorf("Expected offset 0, go %d", offset)
}
_, err = io.Copy(w.file, w.tmpFile)
if err != nil {
os.RemoveAll(w.Path)
}
return err
}