windows.go 26 KB

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