layer.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package server
  2. import (
  3. "crypto/sha256"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "os"
  8. )
  9. type Layer struct {
  10. MediaType string `json:"mediaType"`
  11. Digest string `json:"digest"`
  12. Size int64 `json:"size"`
  13. From string `json:"from,omitempty"`
  14. status string
  15. }
  16. func NewLayer(r io.Reader, mediatype string) (Layer, error) {
  17. blobs, err := GetBlobsPath("")
  18. if err != nil {
  19. return Layer{}, err
  20. }
  21. temp, err := os.CreateTemp(blobs, "sha256-")
  22. if err != nil {
  23. return Layer{}, err
  24. }
  25. defer temp.Close()
  26. defer os.Remove(temp.Name())
  27. sha256sum := sha256.New()
  28. n, err := io.Copy(io.MultiWriter(temp, sha256sum), r)
  29. if err != nil {
  30. return Layer{}, err
  31. }
  32. if err := temp.Close(); err != nil {
  33. return Layer{}, err
  34. }
  35. digest := fmt.Sprintf("sha256:%x", sha256sum.Sum(nil))
  36. blob, err := GetBlobsPath(digest)
  37. if err != nil {
  38. return Layer{}, err
  39. }
  40. status := "using existing layer"
  41. if _, err := os.Stat(blob); err != nil {
  42. status = "creating new layer"
  43. if err := os.Rename(temp.Name(), blob); err != nil {
  44. return Layer{}, err
  45. }
  46. if err := os.Chmod(blob, 0o644); err != nil {
  47. return Layer{}, err
  48. }
  49. }
  50. return Layer{
  51. MediaType: mediatype,
  52. Digest: digest,
  53. Size: n,
  54. status: fmt.Sprintf("%s %s", status, digest),
  55. }, nil
  56. }
  57. func NewLayerFromLayer(digest, mediatype, from string) (Layer, error) {
  58. if digest == "" {
  59. return Layer{}, errors.New("creating new layer from layer with empty digest")
  60. }
  61. blob, err := GetBlobsPath(digest)
  62. if err != nil {
  63. return Layer{}, err
  64. }
  65. fi, err := os.Stat(blob)
  66. if err != nil {
  67. return Layer{}, err
  68. }
  69. return Layer{
  70. MediaType: mediatype,
  71. Digest: digest,
  72. Size: fi.Size(),
  73. From: from,
  74. status: fmt.Sprintf("using existing layer %s", digest),
  75. }, nil
  76. }
  77. func (l *Layer) Open() (io.ReadSeekCloser, error) {
  78. if l.Digest == "" {
  79. return nil, errors.New("opening layer with empty digest")
  80. }
  81. blob, err := GetBlobsPath(l.Digest)
  82. if err != nil {
  83. return nil, err
  84. }
  85. return os.Open(blob)
  86. }
  87. func (l *Layer) Remove() error {
  88. if l.Digest == "" {
  89. return nil
  90. }
  91. // Ignore corrupt manifests to avoid blocking deletion of layers that are freshly orphaned
  92. ms, err := Manifests(true)
  93. if err != nil {
  94. return err
  95. }
  96. for _, m := range ms {
  97. for _, layer := range append(m.Layers, m.Config) {
  98. if layer.Digest == l.Digest {
  99. // something is using this layer
  100. return nil
  101. }
  102. }
  103. }
  104. blob, err := GetBlobsPath(l.Digest)
  105. if err != nil {
  106. return err
  107. }
  108. return os.Remove(blob)
  109. }