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