Tizen_4.0 base
[platform/upstream/docker-engine.git] / daemon / graphdriver / windows / windows.go
1 //+build windows
2
3 package windows
4
5 import (
6         "bufio"
7         "bytes"
8         "encoding/json"
9         "errors"
10         "fmt"
11         "io"
12         "io/ioutil"
13         "os"
14         "path"
15         "path/filepath"
16         "strconv"
17         "strings"
18         "sync"
19         "syscall"
20         "time"
21         "unsafe"
22
23         "github.com/Microsoft/go-winio"
24         "github.com/Microsoft/go-winio/archive/tar"
25         "github.com/Microsoft/go-winio/backuptar"
26         "github.com/Microsoft/hcsshim"
27         "github.com/Sirupsen/logrus"
28         "github.com/docker/docker/daemon/graphdriver"
29         "github.com/docker/docker/pkg/archive"
30         "github.com/docker/docker/pkg/idtools"
31         "github.com/docker/docker/pkg/ioutils"
32         "github.com/docker/docker/pkg/longpath"
33         "github.com/docker/docker/pkg/reexec"
34         "github.com/docker/docker/pkg/system"
35         units "github.com/docker/go-units"
36         "golang.org/x/sys/windows"
37 )
38
39 // filterDriver is an HCSShim driver type for the Windows Filter driver.
40 const filterDriver = 1
41
42 var (
43         // mutatedFiles is a list of files that are mutated by the import process
44         // and must be backed up and restored.
45         mutatedFiles = map[string]string{
46                 "UtilityVM/Files/EFI/Microsoft/Boot/BCD":      "bcd.bak",
47                 "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG":  "bcd.log.bak",
48                 "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG1": "bcd.log1.bak",
49                 "UtilityVM/Files/EFI/Microsoft/Boot/BCD.LOG2": "bcd.log2.bak",
50         }
51         noreexec = false
52 )
53
54 // init registers the windows graph drivers to the register.
55 func init() {
56         graphdriver.Register("windowsfilter", InitFilter)
57         // DOCKER_WINDOWSFILTER_NOREEXEC allows for inline processing which makes
58         // debugging issues in the re-exec codepath significantly easier.
59         if os.Getenv("DOCKER_WINDOWSFILTER_NOREEXEC") != "" {
60                 logrus.Warnf("WindowsGraphDriver is set to not re-exec. This is intended for debugging purposes only.")
61                 noreexec = true
62         } else {
63                 reexec.Register("docker-windows-write-layer", writeLayerReexec)
64         }
65 }
66
67 type checker struct {
68 }
69
70 func (c *checker) IsMounted(path string) bool {
71         return false
72 }
73
74 // Driver represents a windows graph driver.
75 type Driver struct {
76         // info stores the shim driver information
77         info hcsshim.DriverInfo
78         ctr  *graphdriver.RefCounter
79         // it is safe for windows to use a cache here because it does not support
80         // restoring containers when the daemon dies.
81         cacheMu sync.Mutex
82         cache   map[string]string
83 }
84
85 // InitFilter returns a new Windows storage filter driver.
86 func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
87         logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
88
89         fsType, err := getFileSystemType(string(home[0]))
90         if err != nil {
91                 return nil, err
92         }
93         if strings.ToLower(fsType) == "refs" {
94                 return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
95         }
96
97         if err := idtools.MkdirAllAs(home, 0700, 0, 0); err != nil {
98                 return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
99         }
100
101         d := &Driver{
102                 info: hcsshim.DriverInfo{
103                         HomeDir: home,
104                         Flavour: filterDriver,
105                 },
106                 cache: make(map[string]string),
107                 ctr:   graphdriver.NewRefCounter(&checker{}),
108         }
109         return d, nil
110 }
111
112 // win32FromHresult is a helper function to get the win32 error code from an HRESULT
113 func win32FromHresult(hr uintptr) uintptr {
114         if hr&0x1fff0000 == 0x00070000 {
115                 return hr & 0xffff
116         }
117         return hr
118 }
119
120 // getFileSystemType obtains the type of a file system through GetVolumeInformation
121 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
122 func getFileSystemType(drive string) (fsType string, hr error) {
123         var (
124                 modkernel32              = windows.NewLazySystemDLL("kernel32.dll")
125                 procGetVolumeInformation = modkernel32.NewProc("GetVolumeInformationW")
126                 buf                      = make([]uint16, 255)
127                 size                     = syscall.MAX_PATH + 1
128         )
129         if len(drive) != 1 {
130                 hr = errors.New("getFileSystemType must be called with a drive letter")
131                 return
132         }
133         drive += `:\`
134         n := uintptr(unsafe.Pointer(nil))
135         r0, _, _ := syscall.Syscall9(procGetVolumeInformation.Addr(), 8, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(drive))), n, n, n, n, n, uintptr(unsafe.Pointer(&buf[0])), uintptr(size), 0)
136         if int32(r0) < 0 {
137                 hr = syscall.Errno(win32FromHresult(r0))
138         }
139         fsType = syscall.UTF16ToString(buf)
140         return
141 }
142
143 // String returns the string representation of a driver. This should match
144 // the name the graph driver has been registered with.
145 func (d *Driver) String() string {
146         return "windowsfilter"
147 }
148
149 // Status returns the status of the driver.
150 func (d *Driver) Status() [][2]string {
151         return [][2]string{
152                 {"Windows", ""},
153         }
154 }
155
156 // panicIfUsedByLcow does exactly what it says.
157 // TODO @jhowardmsft - this is a temporary measure for the bring-up of
158 // Linux containers on Windows. It is a failsafe to ensure that the right
159 // graphdriver is used.
160 func panicIfUsedByLcow() {
161         if system.LCOWSupported() {
162                 panic("inconsistency - windowsfilter graphdriver should not be used when in LCOW mode")
163         }
164 }
165
166 // Exists returns true if the given id is registered with this driver.
167 func (d *Driver) Exists(id string) bool {
168         panicIfUsedByLcow()
169         rID, err := d.resolveID(id)
170         if err != nil {
171                 return false
172         }
173         result, err := hcsshim.LayerExists(d.info, rID)
174         if err != nil {
175                 return false
176         }
177         return result
178 }
179
180 // CreateReadWrite creates a layer that is writable for use as a container
181 // file system.
182 func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
183         panicIfUsedByLcow()
184         if opts != nil {
185                 return d.create(id, parent, opts.MountLabel, false, opts.StorageOpt)
186         }
187         return d.create(id, parent, "", false, nil)
188 }
189
190 // Create creates a new read-only layer with the given id.
191 func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
192         panicIfUsedByLcow()
193         if opts != nil {
194                 return d.create(id, parent, opts.MountLabel, true, opts.StorageOpt)
195         }
196         return d.create(id, parent, "", true, nil)
197 }
198
199 func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt map[string]string) error {
200         rPId, err := d.resolveID(parent)
201         if err != nil {
202                 return err
203         }
204
205         parentChain, err := d.getLayerChain(rPId)
206         if err != nil {
207                 return err
208         }
209
210         var layerChain []string
211
212         if rPId != "" {
213                 parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
214                 if err != nil {
215                         return err
216                 }
217                 if _, err := os.Stat(filepath.Join(parentPath, "Files")); err == nil {
218                         // This is a legitimate parent layer (not the empty "-init" layer),
219                         // so include it in the layer chain.
220                         layerChain = []string{parentPath}
221                 }
222         }
223
224         layerChain = append(layerChain, parentChain...)
225
226         if readOnly {
227                 if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
228                         return err
229                 }
230         } else {
231                 var parentPath string
232                 if len(layerChain) != 0 {
233                         parentPath = layerChain[0]
234                 }
235
236                 if err := hcsshim.CreateSandboxLayer(d.info, id, parentPath, layerChain); err != nil {
237                         return err
238                 }
239
240                 storageOptions, err := parseStorageOpt(storageOpt)
241                 if err != nil {
242                         return fmt.Errorf("Failed to parse storage options - %s", err)
243                 }
244
245                 if storageOptions.size != 0 {
246                         if err := hcsshim.ExpandSandboxSize(d.info, id, storageOptions.size); err != nil {
247                                 return err
248                         }
249                 }
250         }
251
252         if _, err := os.Lstat(d.dir(parent)); err != nil {
253                 if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
254                         logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
255                 }
256                 return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err)
257         }
258
259         if err := d.setLayerChain(id, layerChain); err != nil {
260                 if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
261                         logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
262                 }
263                 return err
264         }
265
266         return nil
267 }
268
269 // dir returns the absolute path to the layer.
270 func (d *Driver) dir(id string) string {
271         return filepath.Join(d.info.HomeDir, filepath.Base(id))
272 }
273
274 // Remove unmounts and removes the dir information.
275 func (d *Driver) Remove(id string) error {
276         panicIfUsedByLcow()
277         rID, err := d.resolveID(id)
278         if err != nil {
279                 return err
280         }
281
282         // This retry loop is due to a bug in Windows (Internal bug #9432268)
283         // if GetContainers fails with ErrVmcomputeOperationInvalidState
284         // it is a transient error. Retry until it succeeds.
285         var computeSystems []hcsshim.ContainerProperties
286         retryCount := 0
287         osv := system.GetOSVersion()
288         for {
289                 // Get and terminate any template VMs that are currently using the layer.
290                 // Note: It is unfortunate that we end up in the graphdrivers Remove() call
291                 // for both containers and images, but the logic for template VMs is only
292                 // needed for images - specifically we are looking to see if a base layer
293                 // is in use by a template VM as a result of having started a Hyper-V
294                 // container at some point.
295                 //
296                 // We have a retry loop for ErrVmcomputeOperationInvalidState and
297                 // ErrVmcomputeOperationAccessIsDenied as there is a race condition
298                 // in RS1 and RS2 building during enumeration when a silo is going away
299                 // for example under it, in HCS. AccessIsDenied added to fix 30278.
300                 //
301                 // TODO @jhowardmsft - For RS3, we can remove the retries. Also consider
302                 // using platform APIs (if available) to get this more succinctly. Also
303                 // consider enlighting the Remove() interface to have context of why
304                 // the remove is being called - that could improve efficiency by not
305                 // enumerating compute systems during a remove of a container as it's
306                 // not required.
307                 computeSystems, err = hcsshim.GetContainers(hcsshim.ComputeSystemQuery{})
308                 if err != nil {
309                         if (osv.Build < 15139) &&
310                                 ((err == hcsshim.ErrVmcomputeOperationInvalidState) || (err == hcsshim.ErrVmcomputeOperationAccessIsDenied)) {
311                                 if retryCount >= 500 {
312                                         break
313                                 }
314                                 retryCount++
315                                 time.Sleep(10 * time.Millisecond)
316                                 continue
317                         }
318                         return err
319                 }
320                 break
321         }
322
323         for _, computeSystem := range computeSystems {
324                 if strings.Contains(computeSystem.RuntimeImagePath, id) && computeSystem.IsRuntimeTemplate {
325                         container, err := hcsshim.OpenContainer(computeSystem.ID)
326                         if err != nil {
327                                 return err
328                         }
329                         defer container.Close()
330                         err = container.Terminate()
331                         if hcsshim.IsPending(err) {
332                                 err = container.Wait()
333                         } else if hcsshim.IsAlreadyStopped(err) {
334                                 err = nil
335                         }
336
337                         if err != nil {
338                                 return err
339                         }
340                 }
341         }
342
343         layerPath := filepath.Join(d.info.HomeDir, rID)
344         tmpID := fmt.Sprintf("%s-removing", rID)
345         tmpLayerPath := filepath.Join(d.info.HomeDir, tmpID)
346         if err := os.Rename(layerPath, tmpLayerPath); err != nil && !os.IsNotExist(err) {
347                 return err
348         }
349         if err := hcsshim.DestroyLayer(d.info, tmpID); err != nil {
350                 logrus.Errorf("Failed to DestroyLayer %s: %s", id, err)
351         }
352
353         return nil
354 }
355
356 // Get returns the rootfs path for the id. This will mount the dir at its given path.
357 func (d *Driver) Get(id, mountLabel string) (string, error) {
358         panicIfUsedByLcow()
359         logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
360         var dir string
361
362         rID, err := d.resolveID(id)
363         if err != nil {
364                 return "", err
365         }
366         if count := d.ctr.Increment(rID); count > 1 {
367                 return d.cache[rID], nil
368         }
369
370         // Getting the layer paths must be done outside of the lock.
371         layerChain, err := d.getLayerChain(rID)
372         if err != nil {
373                 d.ctr.Decrement(rID)
374                 return "", err
375         }
376
377         if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
378                 d.ctr.Decrement(rID)
379                 return "", err
380         }
381         if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
382                 d.ctr.Decrement(rID)
383                 if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
384                         logrus.Warnf("Failed to Deactivate %s: %s", id, err)
385                 }
386                 return "", err
387         }
388
389         mountPath, err := hcsshim.GetLayerMountPath(d.info, rID)
390         if err != nil {
391                 d.ctr.Decrement(rID)
392                 if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
393                         logrus.Warnf("Failed to Unprepare %s: %s", id, err)
394                 }
395                 if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
396                         logrus.Warnf("Failed to Deactivate %s: %s", id, err)
397                 }
398                 return "", err
399         }
400         d.cacheMu.Lock()
401         d.cache[rID] = mountPath
402         d.cacheMu.Unlock()
403
404         // If the layer has a mount path, use that. Otherwise, use the
405         // folder path.
406         if mountPath != "" {
407                 dir = mountPath
408         } else {
409                 dir = d.dir(id)
410         }
411
412         return dir, nil
413 }
414
415 // Put adds a new layer to the driver.
416 func (d *Driver) Put(id string) error {
417         panicIfUsedByLcow()
418         logrus.Debugf("WindowsGraphDriver Put() id %s", id)
419
420         rID, err := d.resolveID(id)
421         if err != nil {
422                 return err
423         }
424         if count := d.ctr.Decrement(rID); count > 0 {
425                 return nil
426         }
427         d.cacheMu.Lock()
428         _, exists := d.cache[rID]
429         delete(d.cache, rID)
430         d.cacheMu.Unlock()
431
432         // If the cache was not populated, then the layer was left unprepared and deactivated
433         if !exists {
434                 return nil
435         }
436
437         if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
438                 return err
439         }
440         return hcsshim.DeactivateLayer(d.info, rID)
441 }
442
443 // Cleanup ensures the information the driver stores is properly removed.
444 // We use this opportunity to cleanup any -removing folders which may be
445 // still left if the daemon was killed while it was removing a layer.
446 func (d *Driver) Cleanup() error {
447         items, err := ioutil.ReadDir(d.info.HomeDir)
448         if err != nil {
449                 if os.IsNotExist(err) {
450                         return nil
451                 }
452                 return err
453         }
454
455         // Note we don't return an error below - it's possible the files
456         // are locked. However, next time around after the daemon exits,
457         // we likely will be able to to cleanup successfully. Instead we log
458         // warnings if there are errors.
459         for _, item := range items {
460                 if item.IsDir() && strings.HasSuffix(item.Name(), "-removing") {
461                         if err := hcsshim.DestroyLayer(d.info, item.Name()); err != nil {
462                                 logrus.Warnf("Failed to cleanup %s: %s", item.Name(), err)
463                         } else {
464                                 logrus.Infof("Cleaned up %s", item.Name())
465                         }
466                 }
467         }
468
469         return nil
470 }
471
472 // Diff produces an archive of the changes between the specified
473 // layer and its parent layer which may be "".
474 // The layer should be mounted when calling this function
475 func (d *Driver) Diff(id, parent string) (_ io.ReadCloser, err error) {
476         panicIfUsedByLcow()
477         rID, err := d.resolveID(id)
478         if err != nil {
479                 return
480         }
481
482         layerChain, err := d.getLayerChain(rID)
483         if err != nil {
484                 return
485         }
486
487         // this is assuming that the layer is unmounted
488         if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
489                 return nil, err
490         }
491         prepare := func() {
492                 if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
493                         logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
494                 }
495         }
496
497         arch, err := d.exportLayer(rID, layerChain)
498         if err != nil {
499                 prepare()
500                 return
501         }
502         return ioutils.NewReadCloserWrapper(arch, func() error {
503                 err := arch.Close()
504                 prepare()
505                 return err
506         }), nil
507 }
508
509 // Changes produces a list of changes between the specified layer
510 // and its parent layer. If parent is "", then all changes will be ADD changes.
511 // The layer should not be mounted when calling this function.
512 func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
513         panicIfUsedByLcow()
514         rID, err := d.resolveID(id)
515         if err != nil {
516                 return nil, err
517         }
518         parentChain, err := d.getLayerChain(rID)
519         if err != nil {
520                 return nil, err
521         }
522
523         if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
524                 return nil, err
525         }
526         defer func() {
527                 if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
528                         logrus.Errorf("changes() failed to DeactivateLayer %s %s: %s", id, rID, err2)
529                 }
530         }()
531
532         var changes []archive.Change
533         err = winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
534                 r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
535                 if err != nil {
536                         return err
537                 }
538                 defer r.Close()
539
540                 for {
541                         name, _, fileInfo, err := r.Next()
542                         if err == io.EOF {
543                                 return nil
544                         }
545                         if err != nil {
546                                 return err
547                         }
548                         name = filepath.ToSlash(name)
549                         if fileInfo == nil {
550                                 changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
551                         } else {
552                                 // Currently there is no way to tell between an add and a modify.
553                                 changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
554                         }
555                 }
556         })
557         if err != nil {
558                 return nil, err
559         }
560
561         return changes, nil
562 }
563
564 // ApplyDiff extracts the changeset from the given diff into the
565 // layer with the specified id and parent, returning the size of the
566 // new layer in bytes.
567 // The layer should not be mounted when calling this function
568 func (d *Driver) ApplyDiff(id, parent string, diff io.Reader) (int64, error) {
569         panicIfUsedByLcow()
570         var layerChain []string
571         if parent != "" {
572                 rPId, err := d.resolveID(parent)
573                 if err != nil {
574                         return 0, err
575                 }
576                 parentChain, err := d.getLayerChain(rPId)
577                 if err != nil {
578                         return 0, err
579                 }
580                 parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
581                 if err != nil {
582                         return 0, err
583                 }
584                 layerChain = append(layerChain, parentPath)
585                 layerChain = append(layerChain, parentChain...)
586         }
587
588         size, err := d.importLayer(id, diff, layerChain)
589         if err != nil {
590                 return 0, err
591         }
592
593         if err = d.setLayerChain(id, layerChain); err != nil {
594                 return 0, err
595         }
596
597         return size, nil
598 }
599
600 // DiffSize calculates the changes between the specified layer
601 // and its parent and returns the size in bytes of the changes
602 // relative to its base filesystem directory.
603 func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
604         panicIfUsedByLcow()
605         rPId, err := d.resolveID(parent)
606         if err != nil {
607                 return
608         }
609
610         changes, err := d.Changes(id, rPId)
611         if err != nil {
612                 return
613         }
614
615         layerFs, err := d.Get(id, "")
616         if err != nil {
617                 return
618         }
619         defer d.Put(id)
620
621         return archive.ChangesSize(layerFs, changes), nil
622 }
623
624 // GetMetadata returns custom driver information.
625 func (d *Driver) GetMetadata(id string) (map[string]string, error) {
626         panicIfUsedByLcow()
627         m := make(map[string]string)
628         m["dir"] = d.dir(id)
629         return m, nil
630 }
631
632 func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
633         t := tar.NewWriter(w)
634         for {
635                 name, size, fileInfo, err := r.Next()
636                 if err == io.EOF {
637                         break
638                 }
639                 if err != nil {
640                         return err
641                 }
642                 if fileInfo == nil {
643                         // Write a whiteout file.
644                         hdr := &tar.Header{
645                                 Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), archive.WhiteoutPrefix+filepath.Base(name))),
646                         }
647                         err := t.WriteHeader(hdr)
648                         if err != nil {
649                                 return err
650                         }
651                 } else {
652                         err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
653                         if err != nil {
654                                 return err
655                         }
656                 }
657         }
658         return t.Close()
659 }
660
661 // exportLayer generates an archive from a layer based on the given ID.
662 func (d *Driver) exportLayer(id string, parentLayerPaths []string) (io.ReadCloser, error) {
663         archive, w := io.Pipe()
664         go func() {
665                 err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
666                         r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
667                         if err != nil {
668                                 return err
669                         }
670
671                         err = writeTarFromLayer(r, w)
672                         cerr := r.Close()
673                         if err == nil {
674                                 err = cerr
675                         }
676                         return err
677                 })
678                 w.CloseWithError(err)
679         }()
680
681         return archive, nil
682 }
683
684 // writeBackupStreamFromTarAndSaveMutatedFiles reads data from a tar stream and
685 // writes it to a backup stream, and also saves any files that will be mutated
686 // by the import layer process to a backup location.
687 func writeBackupStreamFromTarAndSaveMutatedFiles(buf *bufio.Writer, w io.Writer, t *tar.Reader, hdr *tar.Header, root string) (nextHdr *tar.Header, err error) {
688         var bcdBackup *os.File
689         var bcdBackupWriter *winio.BackupFileWriter
690         if backupPath, ok := mutatedFiles[hdr.Name]; ok {
691                 bcdBackup, err = os.Create(filepath.Join(root, backupPath))
692                 if err != nil {
693                         return nil, err
694                 }
695                 defer func() {
696                         cerr := bcdBackup.Close()
697                         if err == nil {
698                                 err = cerr
699                         }
700                 }()
701
702                 bcdBackupWriter = winio.NewBackupFileWriter(bcdBackup, false)
703                 defer func() {
704                         cerr := bcdBackupWriter.Close()
705                         if err == nil {
706                                 err = cerr
707                         }
708                 }()
709
710                 buf.Reset(io.MultiWriter(w, bcdBackupWriter))
711         } else {
712                 buf.Reset(w)
713         }
714
715         defer func() {
716                 ferr := buf.Flush()
717                 if err == nil {
718                         err = ferr
719                 }
720         }()
721
722         return backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
723 }
724
725 func writeLayerFromTar(r io.Reader, w hcsshim.LayerWriter, root string) (int64, error) {
726         t := tar.NewReader(r)
727         hdr, err := t.Next()
728         totalSize := int64(0)
729         buf := bufio.NewWriter(nil)
730         for err == nil {
731                 base := path.Base(hdr.Name)
732                 if strings.HasPrefix(base, archive.WhiteoutPrefix) {
733                         name := path.Join(path.Dir(hdr.Name), base[len(archive.WhiteoutPrefix):])
734                         err = w.Remove(filepath.FromSlash(name))
735                         if err != nil {
736                                 return 0, err
737                         }
738                         hdr, err = t.Next()
739                 } else if hdr.Typeflag == tar.TypeLink {
740                         err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
741                         if err != nil {
742                                 return 0, err
743                         }
744                         hdr, err = t.Next()
745                 } else {
746                         var (
747                                 name     string
748                                 size     int64
749                                 fileInfo *winio.FileBasicInfo
750                         )
751                         name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
752                         if err != nil {
753                                 return 0, err
754                         }
755                         err = w.Add(filepath.FromSlash(name), fileInfo)
756                         if err != nil {
757                                 return 0, err
758                         }
759                         hdr, err = writeBackupStreamFromTarAndSaveMutatedFiles(buf, w, t, hdr, root)
760                         totalSize += size
761                 }
762         }
763         if err != io.EOF {
764                 return 0, err
765         }
766         return totalSize, nil
767 }
768
769 // importLayer adds a new layer to the tag and graph store based on the given data.
770 func (d *Driver) importLayer(id string, layerData io.Reader, parentLayerPaths []string) (size int64, err error) {
771         if !noreexec {
772                 cmd := reexec.Command(append([]string{"docker-windows-write-layer", d.info.HomeDir, id}, parentLayerPaths...)...)
773                 output := bytes.NewBuffer(nil)
774                 cmd.Stdin = layerData
775                 cmd.Stdout = output
776                 cmd.Stderr = output
777
778                 if err = cmd.Start(); err != nil {
779                         return
780                 }
781
782                 if err = cmd.Wait(); err != nil {
783                         return 0, fmt.Errorf("re-exec error: %v: output: %s", err, output)
784                 }
785
786                 return strconv.ParseInt(output.String(), 10, 64)
787         }
788         return writeLayer(layerData, d.info.HomeDir, id, parentLayerPaths...)
789 }
790
791 // writeLayerReexec is the re-exec entry point for writing a layer from a tar file
792 func writeLayerReexec() {
793         size, err := writeLayer(os.Stdin, os.Args[1], os.Args[2], os.Args[3:]...)
794         if err != nil {
795                 fmt.Fprint(os.Stderr, err)
796                 os.Exit(1)
797         }
798         fmt.Fprint(os.Stdout, size)
799 }
800
801 // writeLayer writes a layer from a tar file.
802 func writeLayer(layerData io.Reader, home string, id string, parentLayerPaths ...string) (int64, error) {
803         err := winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege})
804         if err != nil {
805                 return 0, err
806         }
807         if noreexec {
808                 defer func() {
809                         if err := winio.DisableProcessPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}); err != nil {
810                                 // This should never happen, but just in case when in debugging mode.
811                                 // See https://github.com/docker/docker/pull/28002#discussion_r86259241 for rationale.
812                                 panic("Failed to disabled process privileges while in non re-exec mode")
813                         }
814                 }()
815         }
816
817         info := hcsshim.DriverInfo{
818                 Flavour: filterDriver,
819                 HomeDir: home,
820         }
821
822         w, err := hcsshim.NewLayerWriter(info, id, parentLayerPaths)
823         if err != nil {
824                 return 0, err
825         }
826
827         size, err := writeLayerFromTar(layerData, w, filepath.Join(home, id))
828         if err != nil {
829                 return 0, err
830         }
831
832         err = w.Close()
833         if err != nil {
834                 return 0, err
835         }
836
837         return size, nil
838 }
839
840 // resolveID computes the layerID information based on the given id.
841 func (d *Driver) resolveID(id string) (string, error) {
842         content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerID"))
843         if os.IsNotExist(err) {
844                 return id, nil
845         } else if err != nil {
846                 return "", err
847         }
848         return string(content), nil
849 }
850
851 // setID stores the layerId in disk.
852 func (d *Driver) setID(id, altID string) error {
853         return ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altID), 0600)
854 }
855
856 // getLayerChain returns the layer chain information.
857 func (d *Driver) getLayerChain(id string) ([]string, error) {
858         jPath := filepath.Join(d.dir(id), "layerchain.json")
859         content, err := ioutil.ReadFile(jPath)
860         if os.IsNotExist(err) {
861                 return nil, nil
862         } else if err != nil {
863                 return nil, fmt.Errorf("Unable to read layerchain file - %s", err)
864         }
865
866         var layerChain []string
867         err = json.Unmarshal(content, &layerChain)
868         if err != nil {
869                 return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err)
870         }
871
872         return layerChain, nil
873 }
874
875 // setLayerChain stores the layer chain information in disk.
876 func (d *Driver) setLayerChain(id string, chain []string) error {
877         content, err := json.Marshal(&chain)
878         if err != nil {
879                 return fmt.Errorf("Failed to marshall layerchain json - %s", err)
880         }
881
882         jPath := filepath.Join(d.dir(id), "layerchain.json")
883         err = ioutil.WriteFile(jPath, content, 0600)
884         if err != nil {
885                 return fmt.Errorf("Unable to write layerchain file - %s", err)
886         }
887
888         return nil
889 }
890
891 type fileGetCloserWithBackupPrivileges struct {
892         path string
893 }
894
895 func (fg *fileGetCloserWithBackupPrivileges) Get(filename string) (io.ReadCloser, error) {
896         if backupPath, ok := mutatedFiles[filename]; ok {
897                 return os.Open(filepath.Join(fg.path, backupPath))
898         }
899
900         var f *os.File
901         // Open the file while holding the Windows backup privilege. This ensures that the
902         // file can be opened even if the caller does not actually have access to it according
903         // to the security descriptor. Also use sequential file access to avoid depleting the
904         // standby list - Microsoft VSO Bug Tracker #9900466
905         err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
906                 path := longpath.AddPrefix(filepath.Join(fg.path, filename))
907                 p, err := syscall.UTF16FromString(path)
908                 if err != nil {
909                         return err
910                 }
911                 const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
912                 h, err := syscall.CreateFile(&p[0], syscall.GENERIC_READ, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS|fileFlagSequentialScan, 0)
913                 if err != nil {
914                         return &os.PathError{Op: "open", Path: path, Err: err}
915                 }
916                 f = os.NewFile(uintptr(h), path)
917                 return nil
918         })
919         return f, err
920 }
921
922 func (fg *fileGetCloserWithBackupPrivileges) Close() error {
923         return nil
924 }
925
926 // DiffGetter returns a FileGetCloser that can read files from the directory that
927 // contains files for the layer differences. Used for direct access for tar-split.
928 func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
929         panicIfUsedByLcow()
930         id, err := d.resolveID(id)
931         if err != nil {
932                 return nil, err
933         }
934
935         return &fileGetCloserWithBackupPrivileges{d.dir(id)}, nil
936 }
937
938 type storageOptions struct {
939         size uint64
940 }
941
942 func parseStorageOpt(storageOpt map[string]string) (*storageOptions, error) {
943         options := storageOptions{}
944
945         // Read size to change the block device size per container.
946         for key, val := range storageOpt {
947                 key := strings.ToLower(key)
948                 switch key {
949                 case "size":
950                         size, err := units.RAMInBytes(val)
951                         if err != nil {
952                                 return nil, err
953                         }
954                         options.size = uint64(size)
955                 default:
956                         return nil, fmt.Errorf("Unknown storage option: %s", key)
957                 }
958         }
959         return &options, nil
960 }