@@ -4,6 +4,7 @@ package windows
44
55import (
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 (
3639func init () {
3740 graphdriver .Register ("windowsfilter" , InitFilter )
3841 graphdriver .Register ("windowsdiff" , InitDiff )
42+ reexec .Register ("docker-windows-write-layer" , writeLayer )
3943}
4044
4145const (
@@ -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.
556569func (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.
684699func (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.
0 commit comments