summaryrefslogtreecommitdiff
path: root/vendor/github.com/containers/storage/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/containers/storage/pkg')
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/cache_linux.go5
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/dump/dump.go230
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/storage_linux.go22
3 files changed, 247 insertions, 10 deletions
diff --git a/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go b/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go
index 56c30e267..5d4befc23 100644
--- a/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go
+++ b/vendor/github.com/containers/storage/pkg/chunked/cache_linux.go
@@ -26,6 +26,8 @@ import (
const (
cacheKey = "chunked-manifest-cache"
cacheVersion = 1
+
+ digestSha256Empty = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
)
type metadata struct {
@@ -650,6 +652,9 @@ func unmarshalToc(manifest []byte) (*internal.TOC, error) {
iter.Skip()
}
}
+ if m.Type == TypeReg && m.Size == 0 && m.Digest == "" {
+ m.Digest = digestSha256Empty
+ }
toc.Entries = append(toc.Entries, m)
}
break
diff --git a/vendor/github.com/containers/storage/pkg/chunked/dump/dump.go b/vendor/github.com/containers/storage/pkg/chunked/dump/dump.go
new file mode 100644
index 000000000..a08928034
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/chunked/dump/dump.go
@@ -0,0 +1,230 @@
+package dump
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "strings"
+ "time"
+ "unicode"
+
+ "github.com/containers/storage/pkg/chunked/internal"
+ "golang.org/x/sys/unix"
+)
+
+const (
+ ESCAPE_STANDARD = 0
+ NOESCAPE_SPACE = 1 << iota
+ ESCAPE_EQUAL
+ ESCAPE_LONE_DASH
+)
+
+func escaped(val string, escape int) string {
+ noescapeSpace := escape&NOESCAPE_SPACE != 0
+ escapeEqual := escape&ESCAPE_EQUAL != 0
+ escapeLoneDash := escape&ESCAPE_LONE_DASH != 0
+
+ length := len(val)
+
+ if escapeLoneDash && val == "-" {
+ return fmt.Sprintf("\\x%.2x", val[0])
+ }
+
+ var result string
+ for i := 0; i < length; i++ {
+ c := val[i]
+ hexEscape := false
+ var special string
+
+ switch c {
+ case '\\':
+ special = "\\\\"
+ case '\n':
+ special = "\\n"
+ case '\r':
+ special = "\\r"
+ case '\t':
+ special = "\\t"
+ case '=':
+ hexEscape = escapeEqual
+ default:
+ if noescapeSpace {
+ hexEscape = !unicode.IsPrint(rune(c))
+ } else {
+ hexEscape = !unicode.IsGraphic(rune(c))
+ }
+ }
+
+ if special != "" {
+ result += special
+ } else if hexEscape {
+ result += fmt.Sprintf("\\x%.2x", c)
+ } else {
+ result += string(c)
+ }
+ }
+ return result
+}
+
+func escapedOptional(val string, escape int) string {
+ if val == "" {
+ return "-"
+ }
+ return escaped(val, escape)
+}
+
+func getStMode(mode uint32, typ string) (uint32, error) {
+ switch typ {
+ case internal.TypeReg, internal.TypeLink:
+ mode |= unix.S_IFREG
+ case internal.TypeChar:
+ mode |= unix.S_IFCHR
+ case internal.TypeBlock:
+ mode |= unix.S_IFBLK
+ case internal.TypeDir:
+ mode |= unix.S_IFDIR
+ case internal.TypeFifo:
+ mode |= unix.S_IFIFO
+ case internal.TypeSymlink:
+ mode |= unix.S_IFLNK
+ default:
+ return 0, fmt.Errorf("unknown type %s", typ)
+ }
+ return mode, nil
+}
+
+func dumpNode(out io.Writer, links map[string]int, verityDigests map[string]string, entry *internal.FileMetadata) error {
+ path := entry.Name
+ if path == "" {
+ path = "/"
+ } else if path[0] != '/' {
+ path = "/" + path
+ }
+
+ if _, err := fmt.Fprint(out, escaped(path, ESCAPE_STANDARD)); err != nil {
+ return err
+ }
+
+ nlinks := links[entry.Name] + links[entry.Linkname] + 1
+ link := ""
+ if entry.Type == internal.TypeLink {
+ link = "@"
+ }
+
+ rdev := unix.Mkdev(uint32(entry.Devmajor), uint32(entry.Devminor))
+
+ entryTime := entry.ModTime
+ if entryTime == nil {
+ t := time.Unix(0, 0)
+ entryTime = &t
+ }
+
+ mode, err := getStMode(uint32(entry.Mode), entry.Type)
+ if err != nil {
+ return err
+ }
+
+ if _, err := fmt.Fprintf(out, " %d %s%o %d %d %d %d %d.%d ", entry.Size,
+ link, mode,
+ nlinks, entry.UID, entry.GID, rdev,
+ entryTime.Unix(), entryTime.Nanosecond()); err != nil {
+ return err
+ }
+
+ var payload string
+ if entry.Linkname != "" {
+ payload = entry.Linkname
+ if entry.Type == internal.TypeLink && payload[0] != '/' {
+ payload = "/" + payload
+ }
+ } else {
+ if len(entry.Digest) > 10 {
+ d := strings.Replace(entry.Digest, "sha256:", "", 1)
+ payload = d[:2] + "/" + d[2:]
+ }
+ }
+
+ if _, err := fmt.Fprintf(out, escapedOptional(payload, ESCAPE_LONE_DASH)); err != nil {
+ return err
+ }
+
+ /* inline content. */
+ if _, err := fmt.Fprint(out, " -"); err != nil {
+ return err
+ }
+
+ /* store the digest. */
+ if _, err := fmt.Fprint(out, " "); err != nil {
+ return err
+ }
+ digest := verityDigests[payload]
+ if _, err := fmt.Fprintf(out, escapedOptional(digest, ESCAPE_LONE_DASH)); err != nil {
+ return err
+ }
+
+ for k, v := range entry.Xattrs {
+ name := escaped(k, ESCAPE_EQUAL)
+ value := escaped(v, ESCAPE_EQUAL)
+
+ if _, err := fmt.Fprintf(out, " %s=%s", name, value); err != nil {
+ return err
+ }
+ }
+ if _, err := fmt.Fprint(out, "\n"); err != nil {
+ return err
+ }
+ return nil
+}
+
+// GenerateDump generates a dump of the TOC in the same format as `composefs-info dump`
+func GenerateDump(tocI interface{}, verityDigests map[string]string) (io.Reader, error) {
+ toc, ok := tocI.(*internal.TOC)
+ if !ok {
+ return nil, fmt.Errorf("invalid TOC type")
+ }
+ pipeR, pipeW := io.Pipe()
+ go func() {
+ closed := false
+ w := bufio.NewWriter(pipeW)
+ defer func() {
+ if !closed {
+ w.Flush()
+ pipeW.Close()
+ }
+ }()
+
+ links := make(map[string]int)
+ for _, e := range toc.Entries {
+ if e.Linkname == "" {
+ continue
+ }
+ links[e.Linkname] = links[e.Linkname] + 1
+ }
+
+ if len(toc.Entries) == 0 || (toc.Entries[0].Name != "" && toc.Entries[0].Name != "/") {
+ root := &internal.FileMetadata{
+ Name: "/",
+ Type: internal.TypeDir,
+ Mode: 0o755,
+ }
+
+ if err := dumpNode(w, links, verityDigests, root); err != nil {
+ pipeW.CloseWithError(err)
+ closed = true
+ return
+ }
+ }
+
+ for _, e := range toc.Entries {
+ if e.Type == internal.TypeChunk {
+ continue
+ }
+ if err := dumpNode(w, links, verityDigests, &e); err != nil {
+ pipeW.CloseWithError(err)
+ closed = true
+ return
+ }
+ }
+ }()
+ return pipeR, nil
+}
diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
index 088c92782..8493a2c19 100644
--- a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
+++ b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
@@ -45,6 +45,7 @@ const (
bigDataKey = "zstd-chunked-manifest"
chunkedData = "zstd-chunked-data"
chunkedLayerDataKey = "zstd-chunked-layer-data"
+ tocKey = "toc"
fileTypeZstdChunked = iota
fileTypeEstargz
@@ -1470,10 +1471,7 @@ func makeEntriesFlat(mergedEntries []internal.FileMetadata) ([]internal.FileMeta
continue
}
if mergedEntries[i].Digest == "" {
- if mergedEntries[i].Size != 0 {
- return nil, fmt.Errorf("missing digest for %q", mergedEntries[i].Name)
- }
- continue
+ return nil, fmt.Errorf("missing digest for %q", mergedEntries[i].Name)
}
digest, err := digest.Parse(mergedEntries[i].Digest)
if err != nil {
@@ -1542,6 +1540,13 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
if err != nil {
return graphdriver.DriverWithDifferOutput{}, err
}
+
+ // Generate the manifest
+ toc, err := unmarshalToc(c.manifest)
+ if err != nil {
+ return graphdriver.DriverWithDifferOutput{}, err
+ }
+
output := graphdriver.DriverWithDifferOutput{
Differ: c,
TarSplit: c.tarSplit,
@@ -1549,6 +1554,9 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
bigDataKey: c.manifest,
chunkedLayerDataKey: lcdBigData,
},
+ Artifacts: map[string]interface{}{
+ tocKey: toc,
+ },
TOCDigest: c.contentDigest,
}
@@ -1563,12 +1571,6 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions, diff
// List of OSTree repositories to use for deduplication
ostreeRepos := strings.Split(c.storeOpts.PullOptions["ostree_repos"], ":")
- // Generate the manifest
- toc, err := unmarshalToc(c.manifest)
- if err != nil {
- return output, err
- }
-
whiteoutConverter := archive.GetWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData)
var missingParts []missingPart