windows.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. //+build windows
  2. package windows
  3. import (
  4. "bufio"
  5. "crypto/sha512"
  6. "encoding/json"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "os"
  11. "path"
  12. "path/filepath"
  13. "strings"
  14. "syscall"
  15. "time"
  16. "unsafe"
  17. "github.com/Microsoft/go-winio"
  18. "github.com/Microsoft/go-winio/archive/tar"
  19. "github.com/Microsoft/go-winio/backuptar"
  20. "github.com/Microsoft/hcsshim"
  21. "github.com/Sirupsen/logrus"
  22. "github.com/docker/docker/daemon/graphdriver"
  23. "github.com/docker/docker/pkg/archive"
  24. "github.com/docker/docker/pkg/chrootarchive"
  25. "github.com/docker/docker/pkg/idtools"
  26. "github.com/docker/docker/pkg/ioutils"
  27. "github.com/docker/docker/pkg/longpath"
  28. "github.com/docker/docker/pkg/system"
  29. "github.com/vbatts/tar-split/tar/storage"
  30. )
  31. // init registers the windows graph drivers to the register.
  32. func init() {
  33. graphdriver.Register("windowsfilter", InitFilter)
  34. graphdriver.Register("windowsdiff", InitDiff)
  35. }
  36. const (
  37. // diffDriver is an hcsshim driver type
  38. diffDriver = iota
  39. // filterDriver is an hcsshim driver type
  40. filterDriver
  41. )
  42. // Driver represents a windows graph driver.
  43. type Driver struct {
  44. // info stores the shim driver information
  45. info hcsshim.DriverInfo
  46. }
  47. var _ graphdriver.DiffGetterDriver = &Driver{}
  48. func isTP5OrOlder() bool {
  49. return system.GetOSVersion().Build <= 14300
  50. }
  51. // InitFilter returns a new Windows storage filter driver.
  52. func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
  53. logrus.Debugf("WindowsGraphDriver InitFilter at %s", home)
  54. d := &Driver{
  55. info: hcsshim.DriverInfo{
  56. HomeDir: home,
  57. Flavour: filterDriver,
  58. },
  59. }
  60. return d, nil
  61. }
  62. // InitDiff returns a new Windows differencing disk driver.
  63. func InitDiff(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
  64. logrus.Debugf("WindowsGraphDriver InitDiff at %s", home)
  65. d := &Driver{
  66. info: hcsshim.DriverInfo{
  67. HomeDir: home,
  68. Flavour: diffDriver,
  69. },
  70. }
  71. return d, nil
  72. }
  73. // String returns the string representation of a driver.
  74. func (d *Driver) String() string {
  75. switch d.info.Flavour {
  76. case diffDriver:
  77. return "windowsdiff"
  78. case filterDriver:
  79. return "windowsfilter"
  80. default:
  81. return "Unknown driver flavour"
  82. }
  83. }
  84. // Status returns the status of the driver.
  85. func (d *Driver) Status() [][2]string {
  86. return [][2]string{
  87. {"Windows", ""},
  88. }
  89. }
  90. // Exists returns true if the given id is registered with this driver.
  91. func (d *Driver) Exists(id string) bool {
  92. rID, err := d.resolveID(id)
  93. if err != nil {
  94. return false
  95. }
  96. result, err := hcsshim.LayerExists(d.info, rID)
  97. if err != nil {
  98. return false
  99. }
  100. return result
  101. }
  102. // CreateReadWrite creates a layer that is writable for use as a container
  103. // file system.
  104. func (d *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[string]string) error {
  105. return d.create(id, parent, mountLabel, false, storageOpt)
  106. }
  107. // Create creates a new read-only layer with the given id.
  108. func (d *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error {
  109. return d.create(id, parent, mountLabel, true, storageOpt)
  110. }
  111. func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt map[string]string) error {
  112. if len(storageOpt) != 0 {
  113. return fmt.Errorf("--storage-opt is not supported for windows")
  114. }
  115. rPId, err := d.resolveID(parent)
  116. if err != nil {
  117. return err
  118. }
  119. parentChain, err := d.getLayerChain(rPId)
  120. if err != nil {
  121. return err
  122. }
  123. var layerChain []string
  124. if rPId != "" {
  125. parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
  126. if err != nil {
  127. return err
  128. }
  129. if _, err := os.Stat(filepath.Join(parentPath, "Files")); err == nil {
  130. // This is a legitimate parent layer (not the empty "-init" layer),
  131. // so include it in the layer chain.
  132. layerChain = []string{parentPath}
  133. }
  134. }
  135. layerChain = append(layerChain, parentChain...)
  136. if readOnly {
  137. if err := hcsshim.CreateLayer(d.info, id, rPId); err != nil {
  138. return err
  139. }
  140. } else {
  141. var parentPath string
  142. if len(layerChain) != 0 {
  143. parentPath = layerChain[0]
  144. }
  145. if isTP5OrOlder() {
  146. // Pre-create the layer directory, providing an ACL to give the Hyper-V Virtual Machines
  147. // group access. This is necessary to ensure that Hyper-V containers can access the
  148. // virtual machine data. This is not necessary post-TP5.
  149. path, err := syscall.UTF16FromString(filepath.Join(d.info.HomeDir, id))
  150. if err != nil {
  151. return err
  152. }
  153. // Give system and administrators full control, and VMs read, write, and execute.
  154. // Mark these ACEs as inherited.
  155. sd, err := winio.SddlToSecurityDescriptor("D:(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FRFWFX;;;S-1-5-83-0)")
  156. if err != nil {
  157. return err
  158. }
  159. err = syscall.CreateDirectory(&path[0], &syscall.SecurityAttributes{
  160. Length: uint32(unsafe.Sizeof(syscall.SecurityAttributes{})),
  161. SecurityDescriptor: uintptr(unsafe.Pointer(&sd[0])),
  162. })
  163. if err != nil {
  164. return err
  165. }
  166. }
  167. if err := hcsshim.CreateSandboxLayer(d.info, id, parentPath, layerChain); err != nil {
  168. return err
  169. }
  170. }
  171. if _, err := os.Lstat(d.dir(parent)); err != nil {
  172. if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
  173. logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
  174. }
  175. return fmt.Errorf("Cannot create layer with missing parent %s: %s", parent, err)
  176. }
  177. if err := d.setLayerChain(id, layerChain); err != nil {
  178. if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil {
  179. logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2)
  180. }
  181. return err
  182. }
  183. return nil
  184. }
  185. // dir returns the absolute path to the layer.
  186. func (d *Driver) dir(id string) string {
  187. return filepath.Join(d.info.HomeDir, filepath.Base(id))
  188. }
  189. // Remove unmounts and removes the dir information.
  190. func (d *Driver) Remove(id string) error {
  191. rID, err := d.resolveID(id)
  192. if err != nil {
  193. return err
  194. }
  195. os.RemoveAll(filepath.Join(d.info.HomeDir, "sysfile-backups", rID)) // ok to fail
  196. return hcsshim.DestroyLayer(d.info, rID)
  197. }
  198. // Get returns the rootfs path for the id. This will mount the dir at it's given path.
  199. func (d *Driver) Get(id, mountLabel string) (string, error) {
  200. logrus.Debugf("WindowsGraphDriver Get() id %s mountLabel %s", id, mountLabel)
  201. var dir string
  202. rID, err := d.resolveID(id)
  203. if err != nil {
  204. return "", err
  205. }
  206. // Getting the layer paths must be done outside of the lock.
  207. layerChain, err := d.getLayerChain(rID)
  208. if err != nil {
  209. return "", err
  210. }
  211. if err := hcsshim.ActivateLayer(d.info, rID); err != nil {
  212. return "", err
  213. }
  214. if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
  215. if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
  216. logrus.Warnf("Failed to Deactivate %s: %s", id, err)
  217. }
  218. return "", err
  219. }
  220. mountPath, err := hcsshim.GetLayerMountPath(d.info, rID)
  221. if err != nil {
  222. if err2 := hcsshim.DeactivateLayer(d.info, rID); err2 != nil {
  223. logrus.Warnf("Failed to Deactivate %s: %s", id, err)
  224. }
  225. return "", err
  226. }
  227. // If the layer has a mount path, use that. Otherwise, use the
  228. // folder path.
  229. if mountPath != "" {
  230. dir = mountPath
  231. } else {
  232. dir = d.dir(id)
  233. }
  234. return dir, nil
  235. }
  236. // Put adds a new layer to the driver.
  237. func (d *Driver) Put(id string) error {
  238. logrus.Debugf("WindowsGraphDriver Put() id %s", id)
  239. rID, err := d.resolveID(id)
  240. if err != nil {
  241. return err
  242. }
  243. if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
  244. return err
  245. }
  246. return hcsshim.DeactivateLayer(d.info, rID)
  247. }
  248. // Cleanup ensures the information the driver stores is properly removed.
  249. func (d *Driver) Cleanup() error {
  250. return nil
  251. }
  252. // Diff produces an archive of the changes between the specified
  253. // layer and its parent layer which may be "".
  254. // The layer should be mounted when calling this function
  255. func (d *Driver) Diff(id, parent string) (_ archive.Archive, err error) {
  256. rID, err := d.resolveID(id)
  257. if err != nil {
  258. return
  259. }
  260. layerChain, err := d.getLayerChain(rID)
  261. if err != nil {
  262. return
  263. }
  264. // this is assuming that the layer is unmounted
  265. if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
  266. return nil, err
  267. }
  268. defer func() {
  269. if err := hcsshim.PrepareLayer(d.info, rID, layerChain); err != nil {
  270. logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
  271. }
  272. }()
  273. arch, err := d.exportLayer(rID, layerChain)
  274. if err != nil {
  275. return
  276. }
  277. return ioutils.NewReadCloserWrapper(arch, func() error {
  278. return arch.Close()
  279. }), nil
  280. }
  281. // Changes produces a list of changes between the specified layer
  282. // and its parent layer. If parent is "", then all changes will be ADD changes.
  283. // The layer should be mounted when calling this function
  284. func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
  285. rID, err := d.resolveID(id)
  286. if err != nil {
  287. return nil, err
  288. }
  289. parentChain, err := d.getLayerChain(rID)
  290. if err != nil {
  291. return nil, err
  292. }
  293. // this is assuming that the layer is unmounted
  294. if err := hcsshim.UnprepareLayer(d.info, rID); err != nil {
  295. return nil, err
  296. }
  297. defer func() {
  298. if err := hcsshim.PrepareLayer(d.info, rID, parentChain); err != nil {
  299. logrus.Warnf("Failed to Deactivate %s: %s", rID, err)
  300. }
  301. }()
  302. r, err := hcsshim.NewLayerReader(d.info, id, parentChain)
  303. if err != nil {
  304. return nil, err
  305. }
  306. defer r.Close()
  307. var changes []archive.Change
  308. for {
  309. name, _, fileInfo, err := r.Next()
  310. if err == io.EOF {
  311. break
  312. }
  313. if err != nil {
  314. return nil, err
  315. }
  316. name = filepath.ToSlash(name)
  317. if fileInfo == nil {
  318. changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeDelete})
  319. } else {
  320. // Currently there is no way to tell between an add and a modify.
  321. changes = append(changes, archive.Change{Path: name, Kind: archive.ChangeModify})
  322. }
  323. }
  324. return changes, nil
  325. }
  326. // ApplyDiff extracts the changeset from the given diff into the
  327. // layer with the specified id and parent, returning the size of the
  328. // new layer in bytes.
  329. // The layer should not be mounted when calling this function
  330. func (d *Driver) ApplyDiff(id, parent string, diff archive.Reader) (int64, error) {
  331. if d.info.Flavour == diffDriver {
  332. start := time.Now().UTC()
  333. logrus.Debugf("WindowsGraphDriver ApplyDiff: Start untar layer")
  334. destination := d.dir(id)
  335. destination = filepath.Dir(destination)
  336. size, err := chrootarchive.ApplyUncompressedLayer(destination, diff, nil)
  337. if err != nil {
  338. return 0, err
  339. }
  340. logrus.Debugf("WindowsGraphDriver ApplyDiff: Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
  341. return size, nil
  342. }
  343. var layerChain []string
  344. if parent != "" {
  345. rPId, err := d.resolveID(parent)
  346. if err != nil {
  347. return 0, err
  348. }
  349. parentChain, err := d.getLayerChain(rPId)
  350. if err != nil {
  351. return 0, err
  352. }
  353. parentPath, err := hcsshim.GetLayerMountPath(d.info, rPId)
  354. if err != nil {
  355. return 0, err
  356. }
  357. layerChain = append(layerChain, parentPath)
  358. layerChain = append(layerChain, parentChain...)
  359. }
  360. size, err := d.importLayer(id, diff, layerChain)
  361. if err != nil {
  362. return 0, err
  363. }
  364. if err = d.setLayerChain(id, layerChain); err != nil {
  365. return 0, err
  366. }
  367. return size, nil
  368. }
  369. // DiffSize calculates the changes between the specified layer
  370. // and its parent and returns the size in bytes of the changes
  371. // relative to its base filesystem directory.
  372. func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
  373. rPId, err := d.resolveID(parent)
  374. if err != nil {
  375. return
  376. }
  377. changes, err := d.Changes(id, rPId)
  378. if err != nil {
  379. return
  380. }
  381. layerFs, err := d.Get(id, "")
  382. if err != nil {
  383. return
  384. }
  385. defer d.Put(id)
  386. return archive.ChangesSize(layerFs, changes), nil
  387. }
  388. // CustomImageInfo is the object returned by the driver describing the base
  389. // image.
  390. type CustomImageInfo struct {
  391. ID string
  392. Name string
  393. Version string
  394. Path string
  395. Size int64
  396. CreatedTime time.Time
  397. OSVersion string `json:"-"`
  398. OSFeatures []string `json:"-"`
  399. }
  400. // GetCustomImageInfos returns the image infos for window specific
  401. // base images which should always be present.
  402. func (d *Driver) GetCustomImageInfos() ([]CustomImageInfo, error) {
  403. strData, err := hcsshim.GetSharedBaseImages()
  404. if err != nil {
  405. return nil, fmt.Errorf("Failed to restore base images: %s", err)
  406. }
  407. type customImageInfoList struct {
  408. Images []CustomImageInfo
  409. }
  410. var infoData customImageInfoList
  411. if err = json.Unmarshal([]byte(strData), &infoData); err != nil {
  412. err = fmt.Errorf("JSON unmarshal returned error=%s", err)
  413. logrus.Error(err)
  414. return nil, err
  415. }
  416. var images []CustomImageInfo
  417. for _, imageData := range infoData.Images {
  418. folderName := filepath.Base(imageData.Path)
  419. // Use crypto hash of the foldername to generate a docker style id.
  420. h := sha512.Sum384([]byte(folderName))
  421. id := fmt.Sprintf("%x", h[:32])
  422. if err := d.Create(id, "", "", nil); err != nil {
  423. return nil, err
  424. }
  425. // Create the alternate ID file.
  426. if err := d.setID(id, folderName); err != nil {
  427. return nil, err
  428. }
  429. imageData.ID = id
  430. // For now, hard code that all base images except nanoserver depend on win32k support
  431. if imageData.Name != "NanoServer" {
  432. imageData.OSFeatures = append(imageData.OSFeatures, "win32k")
  433. }
  434. versionData := strings.Split(imageData.Version, ".")
  435. if len(versionData) != 4 {
  436. logrus.Warn("Could not parse Windows version %s", imageData.Version)
  437. } else {
  438. // Include just major.minor.build, skip the fourth version field, which does not influence
  439. // OS compatibility.
  440. imageData.OSVersion = strings.Join(versionData[:3], ".")
  441. }
  442. images = append(images, imageData)
  443. }
  444. return images, nil
  445. }
  446. // GetMetadata returns custom driver information.
  447. func (d *Driver) GetMetadata(id string) (map[string]string, error) {
  448. m := make(map[string]string)
  449. m["dir"] = d.dir(id)
  450. return m, nil
  451. }
  452. func writeTarFromLayer(r hcsshim.LayerReader, w io.Writer) error {
  453. t := tar.NewWriter(w)
  454. for {
  455. name, size, fileInfo, err := r.Next()
  456. if err == io.EOF {
  457. break
  458. }
  459. if err != nil {
  460. return err
  461. }
  462. if fileInfo == nil {
  463. // Write a whiteout file.
  464. hdr := &tar.Header{
  465. Name: filepath.ToSlash(filepath.Join(filepath.Dir(name), archive.WhiteoutPrefix+filepath.Base(name))),
  466. }
  467. err := t.WriteHeader(hdr)
  468. if err != nil {
  469. return err
  470. }
  471. } else {
  472. err = backuptar.WriteTarFileFromBackupStream(t, r, name, size, fileInfo)
  473. if err != nil {
  474. return err
  475. }
  476. }
  477. }
  478. return t.Close()
  479. }
  480. // exportLayer generates an archive from a layer based on the given ID.
  481. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) {
  482. var r hcsshim.LayerReader
  483. r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths)
  484. if err != nil {
  485. return nil, err
  486. }
  487. archive, w := io.Pipe()
  488. go func() {
  489. err := writeTarFromLayer(r, w)
  490. cerr := r.Close()
  491. if err == nil {
  492. err = cerr
  493. }
  494. w.CloseWithError(err)
  495. }()
  496. return archive, nil
  497. }
  498. func writeLayerFromTar(r archive.Reader, w hcsshim.LayerWriter) (int64, error) {
  499. t := tar.NewReader(r)
  500. hdr, err := t.Next()
  501. totalSize := int64(0)
  502. buf := bufio.NewWriter(nil)
  503. for err == nil {
  504. base := path.Base(hdr.Name)
  505. if strings.HasPrefix(base, archive.WhiteoutPrefix) {
  506. name := path.Join(path.Dir(hdr.Name), base[len(archive.WhiteoutPrefix):])
  507. err = w.Remove(filepath.FromSlash(name))
  508. if err != nil {
  509. return 0, err
  510. }
  511. hdr, err = t.Next()
  512. } else if hdr.Typeflag == tar.TypeLink {
  513. err = w.AddLink(filepath.FromSlash(hdr.Name), filepath.FromSlash(hdr.Linkname))
  514. if err != nil {
  515. return 0, err
  516. }
  517. hdr, err = t.Next()
  518. } else {
  519. var (
  520. name string
  521. size int64
  522. fileInfo *winio.FileBasicInfo
  523. )
  524. name, size, fileInfo, err = backuptar.FileInfoFromHeader(hdr)
  525. if err != nil {
  526. return 0, err
  527. }
  528. err = w.Add(filepath.FromSlash(name), fileInfo)
  529. if err != nil {
  530. return 0, err
  531. }
  532. buf.Reset(w)
  533. // Add the Hyper-V Virutal Machine group ACE to the security descriptor
  534. // for TP5 so that Xenons can access all files. This is not necessary
  535. // for post-TP5 builds.
  536. if isTP5OrOlder() {
  537. if sddl, ok := hdr.Winheaders["sd"]; ok {
  538. var ace string
  539. if hdr.Typeflag == tar.TypeDir {
  540. ace = "(A;OICI;0x1200a9;;;S-1-5-83-0)"
  541. } else {
  542. ace = "(A;;0x1200a9;;;S-1-5-83-0)"
  543. }
  544. if hdr.Winheaders["sd"], ok = addAceToSddlDacl(sddl, ace); !ok {
  545. logrus.Debugf("failed to add VM ACE to %s", sddl)
  546. }
  547. }
  548. }
  549. hdr, err = backuptar.WriteBackupStreamFromTarFile(buf, t, hdr)
  550. ferr := buf.Flush()
  551. if ferr != nil {
  552. err = ferr
  553. }
  554. totalSize += size
  555. }
  556. }
  557. if err != io.EOF {
  558. return 0, err
  559. }
  560. return totalSize, nil
  561. }
  562. func addAceToSddlDacl(sddl, ace string) (string, bool) {
  563. daclStart := strings.Index(sddl, "D:")
  564. if daclStart < 0 {
  565. return sddl, false
  566. }
  567. dacl := sddl[daclStart:]
  568. daclEnd := strings.Index(dacl, "S:")
  569. if daclEnd < 0 {
  570. daclEnd = len(dacl)
  571. }
  572. dacl = dacl[:daclEnd]
  573. if strings.Contains(dacl, ace) {
  574. return sddl, true
  575. }
  576. i := 2
  577. for i+1 < len(dacl) {
  578. if dacl[i] != '(' {
  579. return sddl, false
  580. }
  581. if dacl[i+1] == 'A' {
  582. break
  583. }
  584. i += 2
  585. for p := 1; i < len(dacl) && p > 0; i++ {
  586. if dacl[i] == '(' {
  587. p++
  588. } else if dacl[i] == ')' {
  589. p--
  590. }
  591. }
  592. }
  593. return sddl[:daclStart+i] + ace + sddl[daclStart+i:], true
  594. }
  595. // importLayer adds a new layer to the tag and graph store based on the given data.
  596. func (d *Driver) importLayer(id string, layerData archive.Reader, parentLayerPaths []string) (size int64, err error) {
  597. var w hcsshim.LayerWriter
  598. w, err = hcsshim.NewLayerWriter(d.info, id, parentLayerPaths)
  599. if err != nil {
  600. return
  601. }
  602. size, err = writeLayerFromTar(layerData, w)
  603. if err != nil {
  604. w.Close()
  605. return
  606. }
  607. err = w.Close()
  608. if err != nil {
  609. return
  610. }
  611. return
  612. }
  613. // resolveID computes the layerID information based on the given id.
  614. func (d *Driver) resolveID(id string) (string, error) {
  615. content, err := ioutil.ReadFile(filepath.Join(d.dir(id), "layerID"))
  616. if os.IsNotExist(err) {
  617. return id, nil
  618. } else if err != nil {
  619. return "", err
  620. }
  621. return string(content), nil
  622. }
  623. // setID stores the layerId in disk.
  624. func (d *Driver) setID(id, altID string) error {
  625. err := ioutil.WriteFile(filepath.Join(d.dir(id), "layerId"), []byte(altID), 0600)
  626. if err != nil {
  627. return err
  628. }
  629. return nil
  630. }
  631. // getLayerChain returns the layer chain information.
  632. func (d *Driver) getLayerChain(id string) ([]string, error) {
  633. jPath := filepath.Join(d.dir(id), "layerchain.json")
  634. content, err := ioutil.ReadFile(jPath)
  635. if os.IsNotExist(err) {
  636. return nil, nil
  637. } else if err != nil {
  638. return nil, fmt.Errorf("Unable to read layerchain file - %s", err)
  639. }
  640. var layerChain []string
  641. err = json.Unmarshal(content, &layerChain)
  642. if err != nil {
  643. return nil, fmt.Errorf("Failed to unmarshall layerchain json - %s", err)
  644. }
  645. return layerChain, nil
  646. }
  647. // setLayerChain stores the layer chain information in disk.
  648. func (d *Driver) setLayerChain(id string, chain []string) error {
  649. content, err := json.Marshal(&chain)
  650. if err != nil {
  651. return fmt.Errorf("Failed to marshall layerchain json - %s", err)
  652. }
  653. jPath := filepath.Join(d.dir(id), "layerchain.json")
  654. err = ioutil.WriteFile(jPath, content, 0600)
  655. if err != nil {
  656. return fmt.Errorf("Unable to write layerchain file - %s", err)
  657. }
  658. return nil
  659. }
  660. type fileGetCloserWithBackupPrivileges struct {
  661. path string
  662. }
  663. func (fg *fileGetCloserWithBackupPrivileges) Get(filename string) (io.ReadCloser, error) {
  664. var f *os.File
  665. // Open the file while holding the Windows backup privilege. This ensures that the
  666. // file can be opened even if the caller does not actually have access to it according
  667. // to the security descriptor.
  668. err := winio.RunWithPrivilege(winio.SeBackupPrivilege, func() error {
  669. path := longpath.AddPrefix(filepath.Join(fg.path, filename))
  670. p, err := syscall.UTF16FromString(path)
  671. if err != nil {
  672. return err
  673. }
  674. h, err := syscall.CreateFile(&p[0], syscall.GENERIC_READ, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
  675. if err != nil {
  676. return &os.PathError{Op: "open", Path: path, Err: err}
  677. }
  678. f = os.NewFile(uintptr(h), path)
  679. return nil
  680. })
  681. return f, err
  682. }
  683. func (fg *fileGetCloserWithBackupPrivileges) Close() error {
  684. return nil
  685. }
  686. type fileGetDestroyCloser struct {
  687. storage.FileGetter
  688. path string
  689. }
  690. func (f *fileGetDestroyCloser) Close() error {
  691. // TODO: activate layers and release here?
  692. return os.RemoveAll(f.path)
  693. }
  694. // DiffGetter returns a FileGetCloser that can read files from the directory that
  695. // contains files for the layer differences. Used for direct access for tar-split.
  696. func (d *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
  697. id, err := d.resolveID(id)
  698. if err != nil {
  699. return nil, err
  700. }
  701. return &fileGetCloserWithBackupPrivileges{d.dir(id)}, nil
  702. }