|
@@ -4,6 +4,7 @@ package windows
|
|
|
|
|
|
import (
|
|
|
"bufio"
|
|
|
+ "bytes"
|
|
|
"crypto/sha512"
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
@@ -12,6 +13,7 @@ import (
|
|
|
"os"
|
|
|
"path"
|
|
|
"path/filepath"
|
|
|
+ "strconv"
|
|
|
"strings"
|
|
|
"syscall"
|
|
|
"time"
|
|
@@ -28,6 +30,7 @@ import (
|
|
|
"github.com/docker/docker/pkg/idtools"
|
|
|
"github.com/docker/docker/pkg/ioutils"
|
|
|
"github.com/docker/docker/pkg/longpath"
|
|
|
+ "github.com/docker/docker/pkg/reexec"
|
|
|
"github.com/docker/docker/pkg/system"
|
|
|
"github.com/vbatts/tar-split/tar/storage"
|
|
|
)
|
|
@@ -36,6 +39,7 @@ import (
|
|
|
func init() {
|
|
|
graphdriver.Register("windowsfilter", InitFilter)
|
|
|
graphdriver.Register("windowsdiff", InitDiff)
|
|
|
+ reexec.Register("docker-windows-write-layer", writeLayer)
|
|
|
}
|
|
|
|
|
|
const (
|
|
@@ -308,18 +312,21 @@ func (d *Driver) Diff(id, parent string) (_ archive.Archive, err error) {
|
|
|
if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- defer func() {
|
|
|
+ prepare := func() {
|
|
|
if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
|
|
|
logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
|
|
|
}
|
|
|
- }()
|
|
|
+ }
|
|
|
|
|
|
arch, err := d.exportLayer(rID, layerChain)
|
|
|
if err != nil {
|
|
|
+ prepare()
|
|
|
return
|
|
|
}
|
|
|
return ioutils.NewReadCloserWrapper(arch, func() error {
|
|
|
- return arch.Close()
|
|
|
+ err := arch.Close()
|
|
|
+ prepare()
|
|
|
+ return err
|
|
|
}), nil
|
|
|
}
|
|
|
|
|
@@ -346,29 +353,35 @@ func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
- r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- defer r.Close()
|
|
|
-
|
|
|
var changes []archive.Change
|
|
|
- for {
|
|
|
- name, _, fileInfo, err := r.Next()
|
|
|
- if err == io.EOF {
|
|
|
- break
|
|
|
- }
|
|
|
+ err = winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
|
|
|
+ r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ return err
|
|
|
}
|
|
|
- name = filepath.ToSlash(name)
|
|
|
- if fileInfo == nil {
|
|
|
- changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
|
|
|
- } else {
|
|
|
- // Currently there is no way to tell between an add and a modify.
|
|
|
- changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
|
|
|
+ defer r.Close()
|
|
|
+
|
|
|
+ for {
|
|
|
+ name, _, fileInfo, err := r.Next()
|
|
|
+ if err == io.EOF {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ name = filepath.ToSlash(name)
|
|
|
+ if fileInfo == nil {
|
|
|
+ changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
|
|
|
+ } else {
|
|
|
+ // Currently there is no way to tell between an add and a modify.
|
|
|
+ changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
|
|
|
+ }
|
|
|
}
|
|
|
+ })
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
+
|
|
|
return changes, nil
|
|
|
}
|
|
|
|
|
@@ -554,19 +567,21 @@ func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
|
|
|
|
|
|
// exportLayer generates an archive from a layer based on the given ID.
|
|
|
func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) {
|
|
|
- var r hcsshim.LayerReader
|
|
|
- r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
archive, w := io.Pipe()
|
|
|
go func() {
|
|
|
- err := writeTarFromLayer(r, w)
|
|
|
- cerr := r.Close()
|
|
|
- if err == nil {
|
|
|
- err = cerr
|
|
|
- }
|
|
|
+ err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
|
|
|
+ r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ err = writeTarFromLayer(r, w)
|
|
|
+ cerr := r.Close()
|
|
|
+ if err == nil {
|
|
|
+ err = cerr
|
|
|
+ }
|
|
|
+ return err
|
|
|
+ })
|
|
|
w.CloseWithError(err)
|
|
|
}()
|
|
|
|
|
@@ -682,21 +697,63 @@ func addAceToSddlDacl(sddl, ace string) (string, bool) {
|
|
|
|
|
|
// importLayer adds a new layer to the tag and graph store based on the given data.
|
|
|
func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
|
|
|
- var w hcsshim.LayerWriter
|
|
|
- w, err = hcsshim.NewLayerWriter(d.info, id, parentLayerPaths)
|
|
|
- if err != nil {
|
|
|
+ cmd := reexec.Command(append([]string{"docker-windows-write-layer", d.info.HomeDir, id}, parentLayerPaths...)...)
|
|
|
+ output := bytes.NewBuffer(nil)
|
|
|
+ cmd.Stdin = layerData
|
|
|
+ cmd.Stdout = output
|
|
|
+ cmd.Stderr = output
|
|
|
+
|
|
|
+ if err = cmd.Start(); err != nil {
|
|
|
return
|
|
|
}
|
|
|
- size, err = writeLayerFromTar(layerData, w)
|
|
|
- if err != nil {
|
|
|
- w.Close()
|
|
|
- return
|
|
|
+
|
|
|
+ if err = cmd.Wait(); err != nil {
|
|
|
+ return 0, fmt.Errorf("re-exec error: %v: output: %s", err, output)
|
|
|
}
|
|
|
- err = w.Close()
|
|
|
+
|
|
|
+ return strconv.ParseInt(output.String(), 10, 64)
|
|
|
+}
|
|
|
+
|
|
|
+// writeLayer is the re-exec entry point for writing a layer from a tar file
|
|
|
+func writeLayer() {
|
|
|
+ home := os.Args[1]
|
|
|
+ id := os.Args[2]
|
|
|
+ parentLayerPaths := os.Args[3:]
|
|
|
+
|
|
|
+ err := func() error {
|
|
|
+ err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege})
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ info := hcsshim.DriverInfo{
|
|
|
+ Flavour: filterDriver,
|
|
|
+ HomeDir: home,
|
|
|
+ }
|
|
|
+
|
|
|
+ w, err := hcsshim.NewLayerWriter(info, id, parentLayerPaths)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ size, err := writeLayerFromTar(os.Stdin, w)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ err = w.Close()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ fmt.Fprint(os.Stdout, size)
|
|
|
+ return nil
|
|
|
+ }()
|
|
|
+
|
|
|
if err != nil {
|
|
|
- return
|
|
|
+ fmt.Fprint(os.Stderr, err)
|
|
|
+ os.Exit(1)
|
|
|
}
|
|
|
- return
|
|
|
}
|
|
|
|
|
|
// resolveID computes the layerID information based on the given id.
|