logo

go-deblob

Remove binary blobs from a directory (deprecated, consider <https://git.sr.ht/~lanodan/deblob> instead) git clone https://hacktivis.me/git/go-deblob.git

go-deblob.go (2907B)


  1. // This file is part of https://hacktivis.me/git/go-deblob
  2. // Copyright © 2019 Haelwenn (lanodan) Monnier <contact+go-deblob-notice@hacktivis.me>
  3. // SPDX-License-Identifier: BSD-3-Clause
  4. package main
  5. import (
  6. "bytes"
  7. "fmt"
  8. "git.sr.ht/~sircmpwn/getopt"
  9. "io"
  10. "log"
  11. "os"
  12. "path"
  13. )
  14. var excludes []string
  15. var noop bool
  16. func isBlob(filename string) (result bool) {
  17. result = false
  18. // 512 is larger than needed but it's one physical block size
  19. header := make([]byte, 512)
  20. file, err := os.Open(filename)
  21. if err != nil {
  22. log.Printf("os.Open(%s): %s\n", filename, err)
  23. return
  24. }
  25. defer file.Close()
  26. _, err = file.Read(header)
  27. if err != nil && err != io.EOF {
  28. log.Printf("(%s) os.Read: %s\n", filename, err)
  29. return
  30. }
  31. if bytes.HasPrefix(header, []byte("\x7fELF")) || bytes.HasPrefix(header, []byte("!<arch>\n")) || bytes.HasPrefix(header, []byte("\x55\xAA")) {
  32. result = true
  33. }
  34. return
  35. }
  36. func is_excluded(filename string) bool {
  37. for _, exclude := range excludes {
  38. matched, err := path.Match(exclude, filename)
  39. if err != nil {
  40. log.Printf("path.Match(%s, %s): %s\n", exclude, filename, err)
  41. return false
  42. }
  43. if matched {
  44. return true
  45. }
  46. }
  47. return false
  48. }
  49. func checkDir(dirname string, ignoring bool) {
  50. dirFd, err := os.Open(dirname)
  51. if err != nil {
  52. log.Printf("os.Open(%s): %s\n", dirname, err)
  53. return
  54. }
  55. defer dirFd.Close();
  56. files, err := dirFd.Readdir(0)
  57. if err != nil {
  58. log.Printf("(%s) os.Readdir: %v\n", dirname, err)
  59. return
  60. }
  61. for _, file := range files {
  62. filename := path.Join(dirname, file.Name())
  63. if !ignoring {
  64. ignoring = is_excluded(filename)
  65. }
  66. if file.IsDir() {
  67. checkDir(filename, ignoring)
  68. } else if isBlob(filename) {
  69. if ignoring {
  70. fmt.Printf("ignoring: %s\n", filename)
  71. continue
  72. }
  73. if noop {
  74. fmt.Printf("detected: %s\n", filename)
  75. continue
  76. }
  77. fmt.Printf("removing: %s\n", filename)
  78. err = os.Remove(filename)
  79. if err != nil {
  80. log.Printf("os.Remove(%s): %s\n", filename, err)
  81. }
  82. }
  83. }
  84. }
  85. func usage() {
  86. println("Usage: go-deblob [-e exclude] [-d workdir]")
  87. println(" -e Exclude filepath from removal (defaults to none)")
  88. println(" -d Set working directory (defaults to current dir)")
  89. println(" -n No actual removal, only scan and log")
  90. println("See `man 1 go-deblob` for more information.")
  91. }
  92. func main() {
  93. log.SetFlags(log.Lshortfile)
  94. workdir := "."
  95. opts, _, err := getopt.Getopts(os.Args, "e:d:n")
  96. if err != nil {
  97. log.Fatal(err)
  98. }
  99. for _, opt := range opts {
  100. switch opt.Option {
  101. case 'e':
  102. excludes = append(excludes, string(opt.Value))
  103. case 'd':
  104. workdir = opt.Value
  105. case 'n':
  106. noop = true
  107. default:
  108. usage()
  109. os.Exit(1)
  110. }
  111. }
  112. err = os.Chdir(workdir)
  113. if err != nil {
  114. log.Printf("os.Chdir(%s): %s\n", workdir, err)
  115. os.Exit(1)
  116. }
  117. fmt.Println(":: Checking for blobs")
  118. checkDir(".", false)
  119. fmt.Println(":: Done checking for blobs")
  120. }