windows.go 25 KB

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