Debian package metadata parser
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

package.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package dpkg
  2. import (
  3. "bufio"
  4. "crypto/md5"
  5. "encoding/hex"
  6. "io"
  7. "os"
  8. "path/filepath"
  9. "strings"
  10. )
  11. var (
  12. DebianStatus = "/var/lib/dpkg/status"
  13. DebianInfo = "/var/lib/dpkg/info"
  14. )
  15. // Package describes a package in the dpkg database.
  16. // Fields as described in dpkg/lib/dpkg/parse.c
  17. type Package struct {
  18. Name Name `dpkg:"Package"`
  19. Essential bool
  20. Status Status
  21. Priority Priority
  22. Section string
  23. InstalledSize int64 `dpkg:"Installed-Size"`
  24. Origin string
  25. Maintainer string
  26. Bugs string
  27. Architecture string
  28. Source string
  29. Version string
  30. Revision string
  31. ConfigVersion string `dpkg:"Config-Version"`
  32. Replaces Dependancies
  33. Provides Dependancies
  34. Depends Dependancies
  35. PreDepends Dependancies `dpkg:"Pre-Depends"`
  36. Recommends Dependancies
  37. Suggests Dependancies
  38. Breaks Dependancies
  39. Conflicts Dependancies
  40. Enhances Dependancies
  41. Conffiles Conffiles
  42. Filename string
  43. Size int64
  44. MD5sum string
  45. Description string
  46. Extra map[string]string
  47. }
  48. // Changes lists installed files that don't pass the recorded checksum.
  49. func (pkg Package) Changes() (names []string, err error) {
  50. var (
  51. name = filepath.Join(DebianInfo, string(pkg.Name)+".md5sums")
  52. f *os.File
  53. )
  54. if f, err = os.Open(name); err != nil {
  55. return
  56. }
  57. defer f.Close()
  58. names = make([]string, 0)
  59. var s = bufio.NewScanner(f)
  60. for s.Scan() {
  61. var line = s.Text()
  62. if err = s.Err(); err != nil {
  63. return
  64. }
  65. var part = strings.SplitN(line, " ", 2)
  66. if len(part) != 2 {
  67. continue
  68. }
  69. // Most files start with space in stead of slash
  70. if part[1][0] == ' ' {
  71. part[1] = "/" + part[1][1:]
  72. }
  73. var file *os.File
  74. if file, err = os.Open(part[1]); err != nil {
  75. if os.IsNotExist(err) {
  76. names = append(names, part[1])
  77. err = nil
  78. continue
  79. }
  80. return
  81. }
  82. var hash = md5.New()
  83. if _, err = io.Copy(hash, file); err != nil {
  84. file.Close()
  85. return
  86. }
  87. file.Close()
  88. if hex.EncodeToString(hash.Sum(nil)) != part[0] {
  89. names = append(names, part[1])
  90. }
  91. }
  92. return
  93. }
  94. type StatusParser struct {
  95. r *bufio.Reader
  96. }
  97. func NewStatus(r io.Reader) *StatusParser {
  98. return &StatusParser{bufio.NewReader(r)}
  99. }
  100. func (p *StatusParser) Packages() (pkgs []Package, err error) {
  101. var (
  102. s string
  103. b = bufio.NewReader(p.r)
  104. )
  105. for {
  106. var chunk string
  107. if chunk, err = b.ReadString('\n'); err != nil {
  108. if err == io.EOF {
  109. if strings.TrimSpace(s) != "" {
  110. var pkg Package
  111. if pkg, err = unmarshalPackage([]byte(s)); err != nil {
  112. return nil, err
  113. }
  114. pkgs = append(pkgs, pkg)
  115. }
  116. break
  117. }
  118. return nil, err
  119. }
  120. s += chunk
  121. // Empty line
  122. if chunk == "\n" && strings.TrimSpace(s) != "" {
  123. var pkg Package
  124. if pkg, err = unmarshalPackage([]byte(s)); err != nil {
  125. return nil, err
  126. }
  127. pkgs = append(pkgs, pkg)
  128. s = ""
  129. }
  130. }
  131. return pkgs, nil
  132. }
  133. func unmarshalPackage(b []byte) (Package, error) {
  134. var p Package
  135. return p, Unmarshal(b, &p)
  136. }