Advertisement
Guest User

Untitled

a guest
Jan 26th, 2015
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.86 KB | None | 0 0
  1. // walkFiles starts a goroutine to walk the directory tree at root and send the
  2. // path of each regular file on the string channel. It sends the result of the
  3. // walk on the error channel. If done is closed, walkFiles abandons its work.
  4. func walkFiles(done <-chan struct{}, root string) (<-chan string, <-chan error) {
  5. paths := make(chan string)
  6. errc := make(chan error, 1)
  7. go func() { // HL
  8. // Close the paths channel after Walk returns.
  9. defer close(paths) // HL
  10. // No select needed for this send, since errc is buffered.
  11. errc <- filepath.Walk(root, func(path string, info os.FileInfo, err error) error { // HL
  12. if err != nil {
  13. return err
  14. }
  15. if !info.Mode().IsRegular() {
  16. return nil
  17. }
  18. select {
  19. case paths <- path: // HL
  20. case <-done: // HL
  21. return errors.New("walk canceled")
  22. }
  23. return nil
  24. })
  25. }()
  26. return paths, errc
  27. }
  28.  
  29. // A result is the product of reading and summing a file using MD5.
  30. type result struct {
  31. path string
  32. sum [md5.Size]byte
  33. err error
  34. }
  35.  
  36. // digester reads path names from paths and sends digests of the corresponding
  37. // files on c until either paths or done is closed.
  38. func digester(done <-chan struct{}, paths <-chan string, c chan<- result) {
  39. for path := range paths { // HLpaths
  40. data, err := ioutil.ReadFile(path)
  41. select {
  42. case c <- result{path, md5.Sum(data), err}:
  43. case <-done:
  44. return
  45. }
  46. }
  47. }
  48.  
  49. // MD5All reads all the files in the file tree rooted at root and returns a map
  50. // from file path to the MD5 sum of the file's contents. If the directory walk
  51. // fails or any read operation fails, MD5All returns an error. In that case,
  52. // MD5All does not wait for inflight read operations to complete.
  53. func MD5All(root string) (map[string][md5.Size]byte, error) {
  54. // MD5All closes the done channel when it returns; it may do so before
  55. // receiving all the values from c and errc.
  56. done := make(chan struct{})
  57. defer close(done)
  58.  
  59. paths, errc := walkFiles(done, root)
  60.  
  61. // Start a fixed number of goroutines to read and digest files.
  62. c := make(chan result) // HLc
  63. var wg sync.WaitGroup
  64. const numDigesters = 20
  65. wg.Add(numDigesters)
  66. for i := 0; i < numDigesters; i++ {
  67. go func() {
  68. digester(done, paths, c) // HLc
  69. wg.Done()
  70. }()
  71. }
  72. go func() {
  73. wg.Wait()
  74. close(c) // HLc
  75. }()
  76. // End of pipeline. OMIT
  77.  
  78. m := make(map[string][md5.Size]byte)
  79. for r := range c {
  80. if r.err != nil {
  81. return nil, r.err
  82. }
  83. m[r.path] = r.sum
  84. }
  85. // Check whether the Walk failed.
  86. if err := <-errc; err != nil { // HLerrc
  87. return nil, err
  88. }
  89. return m, nil
  90. }
  91.  
  92. func main() {
  93. // Calculate the MD5 sum of all files under the specified directory,
  94. // then print the results sorted by path name.
  95. m, err := MD5All(os.Args[1])
  96. if err != nil {
  97. fmt.Println(err)
  98. return
  99. }
  100. var paths []string
  101. for path := range m {
  102. paths = append(paths, path)
  103. }
  104. sort.Strings(paths)
  105. for _, path := range paths {
  106. fmt.Printf("%x %s\n", m[path], path)
  107. }
  108. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement