tarsum.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package utils
  2. import (
  3. "archive/tar"
  4. "bytes"
  5. "compress/gzip"
  6. "crypto/sha256"
  7. "encoding/hex"
  8. "hash"
  9. "io"
  10. "sort"
  11. "strconv"
  12. )
  13. type verboseHash struct {
  14. hash.Hash
  15. }
  16. func (h verboseHash) Write(buf []byte) (int, error) {
  17. Debugf("--->%s<---", buf)
  18. return h.Hash.Write(buf)
  19. }
  20. type TarSum struct {
  21. io.Reader
  22. tarR *tar.Reader
  23. tarW *tar.Writer
  24. gz *gzip.Writer
  25. bufTar *bytes.Buffer
  26. bufGz *bytes.Buffer
  27. h hash.Hash
  28. h2 verboseHash
  29. sums []string
  30. finished bool
  31. first bool
  32. }
  33. func (ts *TarSum) encodeHeader(h *tar.Header) error {
  34. for _, elem := range [][2]string{
  35. {"name", h.Name},
  36. {"mode", strconv.Itoa(int(h.Mode))},
  37. {"uid", strconv.Itoa(h.Uid)},
  38. {"gid", strconv.Itoa(h.Gid)},
  39. {"size", strconv.Itoa(int(h.Size))},
  40. {"mtime", strconv.Itoa(int(h.ModTime.UTC().Unix()))},
  41. {"typeflag", string([]byte{h.Typeflag})},
  42. {"linkname", h.Linkname},
  43. {"uname", h.Uname},
  44. {"gname", h.Gname},
  45. {"devmajor", strconv.Itoa(int(h.Devmajor))},
  46. {"devminor", strconv.Itoa(int(h.Devminor))},
  47. // {"atime", strconv.Itoa(int(h.AccessTime.UTC().Unix()))},
  48. // {"ctime", strconv.Itoa(int(h.ChangeTime.UTC().Unix()))},
  49. } {
  50. // Debugf("-->%s<-- -->%s<--", elem[0], elem[1])
  51. if _, err := ts.h.Write([]byte(elem[0] + elem[1])); err != nil {
  52. return err
  53. }
  54. }
  55. return nil
  56. }
  57. func (ts *TarSum) Read(buf []byte) (int, error) {
  58. if ts.gz == nil {
  59. ts.bufTar = bytes.NewBuffer([]byte{})
  60. ts.bufGz = bytes.NewBuffer([]byte{})
  61. ts.tarR = tar.NewReader(ts.Reader)
  62. ts.tarW = tar.NewWriter(ts.bufTar)
  63. ts.gz = gzip.NewWriter(ts.bufGz)
  64. ts.h = sha256.New()
  65. // ts.h = verboseHash{sha256.New()}
  66. ts.h.Reset()
  67. ts.first = true
  68. }
  69. if ts.finished {
  70. return ts.bufGz.Read(buf)
  71. }
  72. buf2 := make([]byte, len(buf), cap(buf))
  73. n, err := ts.tarR.Read(buf2)
  74. if err != nil {
  75. if err == io.EOF {
  76. if _, err := ts.h.Write(buf2[:n]); err != nil {
  77. return 0, err
  78. }
  79. if !ts.first {
  80. ts.sums = append(ts.sums, hex.EncodeToString(ts.h.Sum(nil)))
  81. ts.h.Reset()
  82. } else {
  83. ts.first = false
  84. }
  85. currentHeader, err := ts.tarR.Next()
  86. if err != nil {
  87. if err == io.EOF {
  88. if err := ts.gz.Close(); err != nil {
  89. return 0, err
  90. }
  91. ts.finished = true
  92. return n, nil
  93. }
  94. return n, err
  95. }
  96. if err := ts.encodeHeader(currentHeader); err != nil {
  97. return 0, err
  98. }
  99. if err := ts.tarW.WriteHeader(currentHeader); err != nil {
  100. return 0, err
  101. }
  102. if _, err := ts.tarW.Write(buf2[:n]); err != nil {
  103. return 0, err
  104. }
  105. ts.tarW.Flush()
  106. if _, err := io.Copy(ts.gz, ts.bufTar); err != nil {
  107. return 0, err
  108. }
  109. ts.gz.Flush()
  110. return ts.bufGz.Read(buf)
  111. }
  112. return n, err
  113. }
  114. // Filling the hash buffer
  115. if _, err = ts.h.Write(buf2[:n]); err != nil {
  116. return 0, err
  117. }
  118. // Filling the tar writter
  119. if _, err = ts.tarW.Write(buf2[:n]); err != nil {
  120. return 0, err
  121. }
  122. ts.tarW.Flush()
  123. // Filling the gz writter
  124. if _, err = io.Copy(ts.gz, ts.bufTar); err != nil {
  125. return 0, err
  126. }
  127. ts.gz.Flush()
  128. return ts.bufGz.Read(buf)
  129. }
  130. func (ts *TarSum) Sum(extra []byte) string {
  131. sort.Strings(ts.sums)
  132. h := sha256.New()
  133. for _, sum := range ts.sums {
  134. Debugf("-->%s<--", sum)
  135. h.Write([]byte(sum))
  136. }
  137. if extra != nil {
  138. h.Write(extra)
  139. }
  140. checksum := "tarsum+sha256:" + hex.EncodeToString(h.Sum(nil))
  141. Debugf("checksum processed: %s", checksum)
  142. return checksum
  143. }