...
1 package desktop
2
3 import (
4 "os"
5 "path/filepath"
6 "runtime"
7 "strings"
8 "sync"
9 )
10
11 const bufferSize = 32 * 1024
12
13 type scan struct {
14 e [][]*Entry
15 errs chan error
16 in chan *scanEntry
17 sync.Mutex
18 sync.WaitGroup
19 }
20
21 type scanEntry struct {
22 i int
23 f *os.File
24 }
25
26
27
28 func Scan(dirs []string) ([][]*Entry, error) {
29 s := &scan{e: make([][]*Entry, len(dirs)), errs: make(chan error), in: make(chan *scanEntry)}
30
31 for i := 0; i < runtime.GOMAXPROCS(-1); i++ {
32 go scanner(s)
33 }
34
35 for i, dir := range dirs {
36 i, dir := i, dir
37
38 s.Add(1)
39 go scanDir(i, dir, s)
40 }
41
42 done := make(chan bool, 1)
43 go func() {
44 s.Wait()
45 close(s.in)
46
47 done <- true
48 }()
49
50 select {
51 case err := <-s.errs:
52 return nil, err
53 case <-done:
54 return s.e, nil
55 }
56 }
57
58 func scanner(s *scan) {
59 var (
60 buf = make([]byte, bufferSize)
61 scanEntry *scanEntry
62 entry *Entry
63 err error
64 )
65
66 for scanEntry = range s.in {
67 entry, err = Parse(scanEntry.f, buf)
68 scanEntry.f.Close()
69 if err != nil {
70 s.errs <- err
71 s.Done()
72 return
73 } else if entry == nil {
74 s.Done()
75 continue
76 }
77
78 s.Lock()
79 s.e[scanEntry.i] = append(s.e[scanEntry.i], entry)
80 s.Unlock()
81
82 s.Done()
83 }
84 }
85
86 func scanFunc(i int, s *scan) filepath.WalkFunc {
87 return func(path string, f os.FileInfo, err error) error {
88 s.Add(1)
89
90 go func() {
91 if os.IsNotExist(err) {
92 s.Done()
93 return
94 } else if err != nil {
95 s.errs <- err
96 s.Done()
97 return
98 }
99
100 if f == nil || f.IsDir() || !strings.HasSuffix(strings.ToLower(path), ".desktop") {
101 s.Done()
102 return
103 }
104
105 f, err := os.OpenFile(path, os.O_RDONLY, 0644)
106 if os.IsNotExist(err) {
107 s.Done()
108 return
109 } else if err != nil {
110 s.errs <- err
111 s.Done()
112 return
113 }
114
115 s.in <- &scanEntry{i: i, f: f}
116 }()
117
118 return nil
119 }
120 }
121
122 func scanDir(i int, dir string, s *scan) {
123 defer s.Done()
124
125 err := filepath.Walk(dir, scanFunc(i, s))
126 if os.IsNotExist(err) {
127 return
128 } else if err != nil {
129 s.errs <- err
130 }
131 }
132
View as plain text