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