manifest.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. Copyright The containerd Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package continuity
  14. import (
  15. "fmt"
  16. "io"
  17. "log"
  18. "os"
  19. "sort"
  20. pb "github.com/containerd/continuity/proto"
  21. "github.com/golang/protobuf/proto"
  22. )
  23. // Manifest provides the contents of a manifest. Users of this struct should
  24. // not typically modify any fields directly.
  25. type Manifest struct {
  26. // Resources specifies all the resources for a manifest in order by path.
  27. Resources []Resource
  28. }
  29. func Unmarshal(p []byte) (*Manifest, error) {
  30. var bm pb.Manifest
  31. if err := proto.Unmarshal(p, &bm); err != nil {
  32. return nil, err
  33. }
  34. var m Manifest
  35. for _, b := range bm.Resource {
  36. r, err := fromProto(b)
  37. if err != nil {
  38. return nil, err
  39. }
  40. m.Resources = append(m.Resources, r)
  41. }
  42. return &m, nil
  43. }
  44. func Marshal(m *Manifest) ([]byte, error) {
  45. var bm pb.Manifest
  46. for _, resource := range m.Resources {
  47. bm.Resource = append(bm.Resource, toProto(resource))
  48. }
  49. return proto.Marshal(&bm)
  50. }
  51. func MarshalText(w io.Writer, m *Manifest) error {
  52. var bm pb.Manifest
  53. for _, resource := range m.Resources {
  54. bm.Resource = append(bm.Resource, toProto(resource))
  55. }
  56. return proto.MarshalText(w, &bm)
  57. }
  58. // BuildManifest creates the manifest for the given context
  59. func BuildManifest(ctx Context) (*Manifest, error) {
  60. resourcesByPath := map[string]Resource{}
  61. hardlinks := newHardlinkManager()
  62. if err := ctx.Walk(func(p string, fi os.FileInfo, err error) error {
  63. if err != nil {
  64. return fmt.Errorf("error walking %s: %v", p, err)
  65. }
  66. if p == string(os.PathSeparator) {
  67. // skip root
  68. return nil
  69. }
  70. resource, err := ctx.Resource(p, fi)
  71. if err != nil {
  72. if err == ErrNotFound {
  73. return nil
  74. }
  75. log.Printf("error getting resource %q: %v", p, err)
  76. return err
  77. }
  78. // add to the hardlink manager
  79. if err := hardlinks.Add(fi, resource); err == nil {
  80. // Resource has been accepted by hardlink manager so we don't add
  81. // it to the resourcesByPath until we merge at the end.
  82. return nil
  83. } else if err != errNotAHardLink {
  84. // handle any other case where we have a proper error.
  85. return fmt.Errorf("adding hardlink %s: %v", p, err)
  86. }
  87. resourcesByPath[p] = resource
  88. return nil
  89. }); err != nil {
  90. return nil, err
  91. }
  92. // merge and post-process the hardlinks.
  93. hardlinked, err := hardlinks.Merge()
  94. if err != nil {
  95. return nil, err
  96. }
  97. for _, resource := range hardlinked {
  98. resourcesByPath[resource.Path()] = resource
  99. }
  100. var resources []Resource
  101. for _, resource := range resourcesByPath {
  102. resources = append(resources, resource)
  103. }
  104. sort.Stable(ByPath(resources))
  105. return &Manifest{
  106. Resources: resources,
  107. }, nil
  108. }
  109. // VerifyManifest verifies all the resources in a manifest
  110. // against files from the given context.
  111. func VerifyManifest(ctx Context, manifest *Manifest) error {
  112. for _, resource := range manifest.Resources {
  113. if err := ctx.Verify(resource); err != nil {
  114. return err
  115. }
  116. }
  117. return nil
  118. }
  119. // ApplyManifest applies on the resources in a manifest to
  120. // the given context.
  121. func ApplyManifest(ctx Context, manifest *Manifest) error {
  122. for _, resource := range manifest.Resources {
  123. if err := ctx.Apply(resource); err != nil {
  124. return err
  125. }
  126. }
  127. return nil
  128. }