experimental-cli/project/blob.go

111 lines
2.3 KiB
Go

package main
import (
"bufio"
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"os"
"path"
)
const blobByteLimit = 360_000
func pathAndFilename(mhash string) (dirPath string, fileName string) {
validateMhash(mhash)
b32 := mhash[len(BlobSigil):]
pathChunks := []string{
b32[0:7],
b32[7:14],
b32[14:21],
b32[21:28],
b32[28:35],
b32[35:42],
}
f := fmt.Sprintf("%s.%s", b32[42:49], b32[49:52])
p := path.Join(pigeonBlobDir(), path.Join(pathChunks...))
return p, f
}
// Create a set of nested set of directories to place a blob
// as outlined in bundle spec.
func createBlobDirectory(mhash string) string {
dirPath, fileName := pathAndFilename(mhash)
err := os.MkdirAll(dirPath, 0700)
check(err, "createBlobDirectory: %s", err)
return path.Join(dirPath, fileName)
}
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
func blobExists(mhash string) bool {
p1, fname := pathAndFilename(mhash)
p2 := path.Join(p1, fname)
return fileExists(p2)
}
func addBlob(mhash string, data []byte) string {
size := len(data)
if size > blobByteLimit {
panicf("Expected blob smaller than %d. Got: %d", blobByteLimit, size)
}
blobPath := createBlobDirectory(mhash)
write(blobPath, data)
return mhash
}
func addBlobFromPipe() string {
reader := bufio.NewReader(os.Stdin)
var output []byte
for {
input, err := reader.ReadByte()
if err == io.EOF {
break
}
check(err, "addBlobFromPipe err: %s", err)
output = append(output, input)
}
return addBlob(getMhashForBytes(output), output)
}
func write(path string, data []byte) {
// Open a new file for writing only
file, err := os.OpenFile(
path,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
0600,
)
check(err, "Error writing to %s: %s", path, err)
defer file.Close()
_, err2 := file.Write(data)
check(err2, "Write error (II): %s", err2)
}
func getSha256(data []byte) []byte {
h := sha256.New()
h.Write(data)
return h.Sum(nil)
}
func getMhashForBytes(data []byte) string {
return encodeBlobMhash(getSha256(data))
}
/* getMhashForFile Returns the mHash and data for a path. */
func getMhashForFile(path string) (string, []byte) {
data, err := ioutil.ReadFile(path)
check(err, "Can't open %s", path)
return getMhashForBytes(data), data
}