blob: 1cf948f7c99d4360a915917b2e871087d808604b [file] [log] [blame]
Makoto Onuki620e6ad2017-03-16 09:40:08 -07001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// fileslist.py replacement written in GO, which utilizes multi-cores.
16
17package main
18
19import (
20 "crypto/sha256"
21 "encoding/json"
22 "flag"
23 "fmt"
24 "io"
25 "os"
26 "path/filepath"
27 "runtime"
28 "sort"
29 "strings"
30 "sync"
31)
32
33const (
34 MAX_DEFAULT_PARA = 24
35)
36
37func defaultPara() int {
38 ret := runtime.NumCPU()
39 if ret > MAX_DEFAULT_PARA {
40 return MAX_DEFAULT_PARA
41 }
42 return ret
43}
44
45var (
46 para = flag.Int("para", defaultPara(), "Number of goroutines")
47)
48
49// Represents each file.
50type Node struct {
51 SHA256 string
52 Name string // device side path.
53 Size int64
54 path string // host side path.
55 stat os.FileInfo
56}
57
58func newNode(hostPath string, devicePath string, stat os.FileInfo) Node {
59 return Node{Name: devicePath, path: hostPath, stat: stat}
60}
61
62// Scan a Node and returns true if it should be added to the result.
63func (n *Node) scan() bool {
64 n.Size = n.stat.Size()
65
66 // Calculate SHA256.
67 f, err := os.Open(n.path)
68 if err != nil {
69 // If the file can't be read, it's probably a symlink to an absolute path...
70 // Returns the following to mimic the behavior of fileslist.py.
71 n.SHA256 = "----------------------------------------------------------------"
72 return true
73 }
74 defer f.Close()
75
76 h := sha256.New()
77 if _, err := io.Copy(h, f); err != nil {
78 panic(err)
79 }
80 n.SHA256 = fmt.Sprintf("%x", h.Sum(nil))
81 return true
82}
83
84func main() {
85 flag.Parse()
86
87 allOutput := make([]Node, 0, 1024) // Store all outputs.
88 mutex := &sync.Mutex{} // Guard allOutput
89
90 ch := make(chan Node) // Pass nodes to goroutines.
91
92 var wg sync.WaitGroup // To wait for all goroutines.
93 wg.Add(*para)
94
95 // Scan files in multiple goroutines.
96 for i := 0; i < *para; i++ {
97 go func() {
98 defer wg.Done()
99
100 output := make([]Node, 0, 1024) // Local output list.
101 for node := range ch {
102 if node.scan() {
103 output = append(output, node)
104 }
105 }
106 // Add to the global output list.
107 mutex.Lock()
108 allOutput = append(allOutput, output...)
109 mutex.Unlock()
110 }()
111 }
112
113 // Walk the directories and find files to scan.
114 for _, dir := range flag.Args() {
115 absDir, err := filepath.Abs(dir)
116 if err != nil {
117 panic(err)
118 }
119 deviceRoot := filepath.Clean(absDir + "/..")
120 err = filepath.Walk(dir, func(path string, stat os.FileInfo, err error) error {
121 if err != nil {
122 panic(err)
123 }
124 if stat.IsDir() {
125 return nil
126 }
127 absPath, err := filepath.Abs(path)
128 if err != nil {
129 panic(err)
130 }
131 devicePath, err := filepath.Rel(deviceRoot, absPath)
132 if err != nil {
133 panic(err)
134 }
135 devicePath = "/" + devicePath
136 ch <- newNode(absPath, devicePath, stat)
137 return nil
138 })
139 if err != nil {
140 panic(err)
141 }
142 }
143
144 // Wait until all the goroutines finish.
145 close(ch)
146 wg.Wait()
147
148 // Sort the entries and dump as json.
149 sort.Slice(allOutput, func(i, j int) bool {
150 if allOutput[i].Size > allOutput[j].Size {
151 return true
152 }
153 if allOutput[i].Size == allOutput[j].Size && strings.Compare(allOutput[i].Name, allOutput[j].Name) > 0 {
154 return true
155 }
156 return false
157 })
158
159 j, err := json.MarshalIndent(allOutput, "", " ")
160 if err != nil {
161 panic(nil)
162 }
163
164 fmt.Printf("%s\n", j)
165}