*: refactoring to support streams

when creating a manifest from, or validating, a stream like a tar
archive, it requires thinking about some of the functions differently
than walking a directory tree.

This is the beginning of allowing for such features.

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
Vincent Batts 2016-04-15 18:39:18 -04:00 committed by Stephen Chung
parent 119cdc314c
commit faa80931af
11 changed files with 534 additions and 133 deletions

View file

@ -1,6 +1,7 @@
package mtree
import (
"archive/tar"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
@ -17,7 +18,10 @@ import (
// KeywordFunc is the type of a function called on each file to be included in
// a DirectoryHierarchy, that will produce the string output of the keyword to
// be included for the file entry. Otherwise, empty string.
type KeywordFunc func(path string, info os.FileInfo) (string, error)
// io.Reader `r` is to the file stream for the file payload. While this
// function takes an io.Reader, the caller needs to reset it to the beginning
// for each new KeywordFunc
type KeywordFunc func(path string, info os.FileInfo, r io.Reader) (string, error)
// KeyVal is a "keyword=value"
type KeyVal string
@ -165,7 +169,7 @@ var (
)
var (
modeKeywordFunc = func(path string, info os.FileInfo) (string, error) {
modeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
permissions := info.Mode().Perm()
if os.ModeSetuid&info.Mode() > 0 {
permissions |= (1 << 11)
@ -178,52 +182,43 @@ var (
}
return fmt.Sprintf("mode=%#o", permissions), nil
}
sizeKeywordFunc = func(path string, info os.FileInfo) (string, error) {
sizeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
return fmt.Sprintf("size=%d", info.Size()), nil
}
cksumKeywordFunc = func(path string, info os.FileInfo) (string, error) {
cksumKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
if !info.Mode().IsRegular() {
return "", nil
}
fh, err := os.Open(path)
if err != nil {
return "", err
}
defer fh.Close()
sum, _, err := cksum(fh)
sum, _, err := cksum(r)
if err != nil {
return "", err
}
return fmt.Sprintf("cksum=%d", sum), nil
}
hasherKeywordFunc = func(name string, newHash func() hash.Hash) KeywordFunc {
return func(path string, info os.FileInfo) (string, error) {
return func(path string, info os.FileInfo, r io.Reader) (string, error) {
if !info.Mode().IsRegular() {
return "", nil
}
fh, err := os.Open(path)
if err != nil {
return "", err
}
defer fh.Close()
h := newHash()
if _, err := io.Copy(h, fh); err != nil {
if _, err := io.Copy(h, r); err != nil {
return "", err
}
return fmt.Sprintf("%s=%x", name, h.Sum(nil)), nil
}
}
timeKeywordFunc = func(path string, info os.FileInfo) (string, error) {
timeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
t := info.ModTime().UnixNano()
if t == 0 {
return "time=0.000000000", nil
}
return fmt.Sprintf("time=%d.%9.9d", (t / 1e9), (t % (t / 1e9))), nil
}
linkKeywordFunc = func(path string, info os.FileInfo) (string, error) {
linkKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
if sys, ok := info.Sys().(*tar.Header); ok {
return sys.Linkname, nil
}
if info.Mode()&os.ModeSymlink != 0 {
str, err := os.Readlink(path)
if err != nil {
@ -233,7 +228,7 @@ var (
}
return "", nil
}
typeKeywordFunc = func(path string, info os.FileInfo) (string, error) {
typeKeywordFunc = func(path string, info os.FileInfo, r io.Reader) (string, error) {
if info.Mode().IsDir() {
return "type=dir", nil
}