Skip to content

Commit 4c68381

Browse files
author
John Howard
committed
Merge pull request moby#22728 from Microsoft/jstarks/improve_import
Windows: reexec during layer import
2 parents 0088b8f + b3bc5e0 commit 4c68381

File tree

7 files changed

+192
-79
lines changed

7 files changed

+192
-79
lines changed

daemon/graphdriver/windows/windows.go

Lines changed: 99 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package windows
44

55
import (
66
"bufio"
7+
"bytes"
78
"crypto/sha512"
89
"encoding/json"
910
"fmt"
@@ -12,6 +13,7 @@ import (
1213
"os"
1314
"path"
1415
"path/filepath"
16+
"strconv"
1517
"strings"
1618
"syscall"
1719
"time"
@@ -28,6 +30,7 @@ import (
2830
"github.com/docker/docker/pkg/idtools"
2931
"github.com/docker/docker/pkg/ioutils"
3032
"github.com/docker/docker/pkg/longpath"
33+
"github.com/docker/docker/pkg/reexec"
3134
"github.com/docker/docker/pkg/system"
3235
"github.com/vbatts/tar-split/tar/storage"
3336
)
@@ -36,6 +39,7 @@ import (
3639
func init() {
3740
graphdriver.Register("windowsfilter", InitFilter)
3841
graphdriver.Register("windowsdiff", InitDiff)
42+
reexec.Register("docker-windows-write-layer", writeLayer)
3943
}
4044

4145
const (
@@ -308,18 +312,21 @@ func (d *Driver) Diff(id, parent string) (_ archive.Archive, err error) {
308312
if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
309313
return nil, err
310314
}
311-
defer func() {
315+
prepare := func() {
312316
if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
313317
logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
314318
}
315-
}()
319+
}
316320

317321
arch, err := d.exportLayer(rID, layerChain)
318322
if err != nil {
323+
prepare()
319324
return
320325
}
321326
return ioutils.NewReadCloserWrapper(arch, func() error {
322-
return arch.Close()
327+
err := arch.Close()
328+
prepare()
329+
return err
323330
}), nil
324331
}
325332

@@ -346,29 +353,35 @@ func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
346353
}
347354
}()
348355

349-
r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
350-
if err != nil {
351-
return nil, err
352-
}
353-
defer r.Close()
354-
355356
var changes []archive.Change
356-
for {
357-
name, _, fileInfo, err := r.Next()
358-
if err == io.EOF {
359-
break
360-
}
357+
err = winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
358+
r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
361359
if err != nil {
362-
return nil, err
360+
return err
363361
}
364-
name = filepath.ToSlash(name)
365-
if fileInfo == nil {
366-
changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
367-
} else {
368-
// Currently there is no way to tell between an add and a modify.
369-
changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
362+
defer r.Close()
363+
364+
for {
365+
name, _, fileInfo, err := r.Next()
366+
if err == io.EOF {
367+
return nil
368+
}
369+
if err != nil {
370+
return err
371+
}
372+
name = filepath.ToSlash(name)
373+
if fileInfo == nil {
374+
changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
375+
} else {
376+
// Currently there is no way to tell between an add and a modify.
377+
changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
378+
}
370379
}
380+
})
381+
if err != nil {
382+
return nil, err
371383
}
384+
372385
return changes, nil
373386
}
374387

@@ -554,19 +567,21 @@ func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
554567

555568
// exportLayer generates an archive from a layer based on the given ID.
556569
func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) {
557-
var r hcsshim.LayerReader
558-
r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
559-
if err != nil {
560-
return nil, err
561-
}
562-
563570
archive, w := io.Pipe()
564571
go func() {
565-
err := writeTarFromLayer(r, w)
566-
cerr := r.Close()
567-
if err == nil {
568-
err = cerr
569-
}
572+
err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
573+
r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
574+
if err != nil {
575+
return err
576+
}
577+
578+
err = writeTarFromLayer(r, w)
579+
cerr := r.Close()
580+
if err == nil {
581+
err = cerr
582+
}
583+
return err
584+
})
570585
w.CloseWithError(err)
571586
}()
572587

@@ -682,21 +697,63 @@ func addAceToSddlDacl(sddl, ace string) (string, bool) {
682697

683698
// importLayer adds a new layer to the tag and graph store based on the given data.
684699
func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
685-
var w hcsshim.LayerWriter
686-
w, err = hcsshim.NewLayerWriter(d.info, id, parentLayerPaths)
687-
if err != nil {
700+
cmd := reexec.Command(append([]string{"docker-windows-write-layer", d.info.HomeDir, id}, parentLayerPaths...)...)
701+
output := bytes.NewBuffer(nil)
702+
cmd.Stdin = layerData
703+
cmd.Stdout = output
704+
cmd.Stderr = output
705+
706+
if err = cmd.Start(); err != nil {
688707
return
689708
}
690-
size, err = writeLayerFromTar(layerData, w)
691-
if err != nil {
692-
w.Close()
693-
return
709+
710+
if err = cmd.Wait(); err != nil {
711+
return 0, fmt.Errorf("re-exec error: %v: output: %s", err, output)
694712
}
695-
err = w.Close()
713+
714+
return strconv.ParseInt(output.String(), 10, 64)
715+
}
716+
717+
// writeLayer is the re-exec entry point for writing a layer from a tar file
718+
func writeLayer() {
719+
home := os.Args[1]
720+
id := os.Args[2]
721+
parentLayerPaths := os.Args[3:]
722+
723+
err := func() error {
724+
err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege})
725+
if err != nil {
726+
return err
727+
}
728+
729+
info := hcsshim.DriverInfo{
730+
Flavour: filterDriver,
731+
HomeDir: home,
732+
}
733+
734+
w, err := hcsshim.NewLayerWriter(info, id, parentLayerPaths)
735+
if err != nil {
736+
return err
737+
}
738+
739+
size, err := writeLayerFromTar(os.Stdin, w)
740+
if err != nil {
741+
return err
742+
}
743+
744+
err = w.Close()
745+
if err != nil {
746+
return err
747+
}
748+
749+
fmt.Fprint(os.Stdout, size)
750+
return nil
751+
}()
752+
696753
if err != nil {
697-
return
754+
fmt.Fprint(os.Stderr, err)
755+
os.Exit(1)
698756
}
699-
return
700757
}
701758

702759
// resolveID computes the layerID information based on the given id.

hack/vendor.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ source 'hack/.vendor-helpers.sh'
88
# the following lines are in sorted order, FYI
99
clone git github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
1010
clone git github.com/Microsoft/hcsshim v0.2.2
11-
clone git github.com/Microsoft/go-winio v0.3.0
11+
clone git github.com/Microsoft/go-winio v0.3.4
1212
clone git github.com/Sirupsen/logrus v0.9.0 # logrus is a common dependency among multiple deps
1313
clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
1414
clone git github.com/go-check/check 03a4d9dcf2f92eae8e90ed42aa2656f63fdd0b14 https://github.com/cpuguy83/check.git
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.exe

vendor/src/github.com/Microsoft/go-winio/backuptar/tar.go

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package backuptar
22

33
import (
4+
"encoding/base64"
45
"errors"
56
"fmt"
67
"io"
@@ -29,9 +30,10 @@ const (
2930
)
3031

3132
const (
32-
hdrFileAttributes = "fileattr"
33-
hdrSecurityDescriptor = "sd"
34-
hdrMountPoint = "mountpoint"
33+
hdrFileAttributes = "fileattr"
34+
hdrSecurityDescriptor = "sd"
35+
hdrRawSecurityDescriptor = "rawsd"
36+
hdrMountPoint = "mountpoint"
3537
)
3638

3739
func writeZeroes(w io.Writer, count int64) error {
@@ -108,7 +110,7 @@ func BasicInfoHeader(name string, size int64, fileInfo *winio.FileBasicInfo) *ta
108110
//
109111
// MSWINDOWS.fileattr: The Win32 file attributes, as a decimal value
110112
//
111-
// MSWINDOWS.sd: The Win32 security descriptor, in SDDL (string) format
113+
// MSWINDOWS.rawsd: The Win32 security descriptor, in raw binary format
112114
//
113115
// MSWINDOWS.mountpoint: If present, this is a mount point and not a symlink, even though the type is '2' (symlink)
114116
func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size int64, fileInfo *winio.FileBasicInfo) error {
@@ -133,11 +135,7 @@ func WriteTarFileFromBackupStream(t *tar.Writer, r io.Reader, name string, size
133135
if err != nil {
134136
return err
135137
}
136-
sddl, err := winio.SecurityDescriptorToSddl(sd)
137-
if err != nil {
138-
return err
139-
}
140-
hdr.Winheaders[hdrSecurityDescriptor] = sddl
138+
hdr.Winheaders[hdrRawSecurityDescriptor] = base64.StdEncoding.EncodeToString(sd)
141139

142140
case winio.BackupReparseData:
143141
hdr.Mode |= c_ISLNK
@@ -263,16 +261,28 @@ func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win
263261
// tar file that was not processed, or io.EOF is there are no more.
264262
func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (*tar.Header, error) {
265263
bw := winio.NewBackupStreamWriter(w)
264+
var sd []byte
265+
var err error
266+
// Maintaining old SDDL-based behavior for backward compatibility. All new tar headers written
267+
// by this library will have raw binary for the security descriptor.
266268
if sddl, ok := hdr.Winheaders[hdrSecurityDescriptor]; ok {
267-
sd, err := winio.SddlToSecurityDescriptor(sddl)
269+
sd, err = winio.SddlToSecurityDescriptor(sddl)
270+
if err != nil {
271+
return nil, err
272+
}
273+
}
274+
if sdraw, ok := hdr.Winheaders[hdrRawSecurityDescriptor]; ok {
275+
sd, err = base64.StdEncoding.DecodeString(sdraw)
268276
if err != nil {
269277
return nil, err
270278
}
279+
}
280+
if len(sd) != 0 {
271281
bhdr := winio.BackupHeader{
272282
Id: winio.BackupSecurity,
273283
Size: int64(len(sd)),
274284
}
275-
err = bw.WriteHeader(&bhdr)
285+
err := bw.WriteHeader(&bhdr)
276286
if err != nil {
277287
return nil, err
278288
}
@@ -284,7 +294,7 @@ func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (
284294
if hdr.Typeflag == tar.TypeSymlink {
285295
_, isMountPoint := hdr.Winheaders[hdrMountPoint]
286296
rp := winio.ReparsePoint{
287-
Target: hdr.Linkname,
297+
Target: filepath.FromSlash(hdr.Linkname),
288298
IsMountPoint: isMountPoint,
289299
}
290300
reparse := winio.EncodeReparsePoint(&rp)

0 commit comments

Comments
 (0)