windows.go 26 KB

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