rootfs runs

This commit is contained in:
Motiejus Jakštys 2021-05-24 00:11:57 +03:00
parent 4d6476cca9
commit ce445b19b7

View File

@ -58,48 +58,109 @@ type dockerManifestJSON []struct {
// 4. go through // 4. go through
func (r *cmdRootFS) rootfs(in io.ReadSeeker, out io.Writer) error { func (r *cmdRootFS) rootfs(in io.ReadSeeker, out io.Writer) error {
tr := tar.NewReader(in) tr := tar.NewReader(in)
tw := tar.NewWriter(out)
// layerOffsets maps a layer name (a9b123c0daa/layer.tar) to it's offset
layerOffsets := map[string]int64{} layerOffsets := map[string]int64{}
// manifest is the docker manifest in the image
var manifest dockerManifestJSON var manifest dockerManifestJSON
// phase 1: get layer offsets and manifest.json // phase 1: get layer offsets and manifest.json
for { for {
hdrIn, err := tr.Next() hdr, err := tr.Next()
if err == io.EOF { if err == io.EOF {
break break
} }
if hdrIn.Typeflag != tar.TypeReg { if hdr.Typeflag != tar.TypeReg {
continue continue
} }
switch { switch {
case hdrIn.Name == _manifestJSON: case hdr.Name == _manifestJSON:
dec := json.NewDecoder(tr) dec := json.NewDecoder(tr)
if err := dec.Decode(&manifest); err != nil { if err := dec.Decode(&manifest); err != nil {
return fmt.Errorf("decode manifest.json: %w", err) return fmt.Errorf("decode manifest.json: %w", err)
} }
case strings.HasSuffix(hdrIn.Name, "/layer.tar"): case strings.HasSuffix(hdr.Name, "/layer.tar"):
here, err := in.Seek(0, io.SeekCurrent) here, err := in.Seek(0, io.SeekCurrent)
if err != nil { if err != nil {
return fmt.Errorf("seek: %w", err) return fmt.Errorf("seek: %w", err)
} }
layers[hdrIn.Name] = here layerOffsets[hdr.Name] = here
//fmt.Printf("%s\t%x\n", hdr.Name, here)
} }
} }
// phase 1.5: enumerate layers // phase 1.5: enumerate layers
layers := make([]int64, len(layers)) layers := make([]int64, len(layerOffsets))
for i, name := range manifest.Layers { for i, name := range manifest[0].Layers {
layers[i] = layerOffsets[name] layers[i] = layerOffsets[name]
} }
// phase 2: iterate through all layers and extract filenames // file2layer maps a filename to layer number (index in "layers")
// to files and ordered file2layer := map[string]int{}
files := map[string]struct{
layer string
fmt.Printf("layers: %+v\n", layers) // phase 2: iterate through all layers and save filenames
// for all kinds of files.
return nil for i, offset := range layers {
//return tw.Close() if _, err := in.Seek(offset, io.SeekStart); err != nil {
fmt.Errorf("seek: %w", err)
}
tr = tar.NewReader(in)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
file2layer[hdr.Name] = i
}
}
// phase 3: iterate through all layers and write files.
for i, offset := range layers {
if _, err := in.Seek(offset, io.SeekStart); err != nil {
fmt.Errorf("seek: %w", err)
}
tr = tar.NewReader(in)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if file2layer[hdr.Name] != i {
continue
}
hdrOut := &tar.Header{
Typeflag: hdr.Typeflag,
Name: hdr.Name,
Linkname: hdr.Linkname,
Size: hdr.Size,
Mode: int64(hdr.Mode & 0777),
Uid: hdr.Uid,
Gid: hdr.Gid,
Uname: hdr.Uname,
Gname: hdr.Gname,
ModTime: hdr.ModTime,
Devmajor: hdr.Devmajor,
Devminor: hdr.Devminor,
Format: tar.FormatGNU,
}
if err := tw.WriteHeader(hdrOut); err != nil {
return err
}
if hdr.Typeflag == tar.TypeReg {
if _, err := io.Copy(tw, tr); err != nil {
return err
}
}
}
}
return tw.Close()
} }