windows.go 27 KB

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