2014-07-28 20:28:59 +00:00
|
|
|
package pointer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
2014-08-05 16:06:22 +00:00
|
|
|
"github.com/github/git-media/gitmedia"
|
2014-07-28 20:28:59 +00:00
|
|
|
"hash"
|
|
|
|
"io"
|
|
|
|
"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
|
|
|
|
tmpFile *os.File
|
|
|
|
hasher hash.Hash
|
|
|
|
}
|
|
|
|
|
|
|
|
func newFile(path, sha256Sig string) (*consistentFileWriter, error) {
|
2014-07-29 00:07:38 +00:00
|
|
|
_, err := os.Stat(path)
|
|
|
|
if err == nil {
|
|
|
|
return nil, fmt.Errorf("File exists: %s", path)
|
2014-07-28 20:28:59 +00:00
|
|
|
}
|
|
|
|
|
2014-08-05 16:06:22 +00:00
|
|
|
tmpFile, err := gitmedia.TempFile(sha256Sig)
|
2014-07-28 20:28:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
h := sha256.New()
|
|
|
|
w := io.MultiWriter(tmpFile, h)
|
2014-07-29 00:07:38 +00:00
|
|
|
return &consistentFileWriter{path, sha256Sig, w, tmpFile, h}, nil
|
2014-07-28 20:28:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (w *consistentFileWriter) Write(p []byte) (int, error) {
|
|
|
|
return w.writer.Write(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *consistentFileWriter) Close() error {
|
2014-08-05 16:06:22 +00:00
|
|
|
defer os.RemoveAll(w.tmpFile.Name())
|
2014-07-28 20:28:59 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2014-08-05 16:06:22 +00:00
|
|
|
w.tmpFile.Close()
|
|
|
|
return os.Rename(w.tmpFile.Name(), w.Path)
|
2014-07-28 20:28:59 +00:00
|
|
|
}
|