-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathmain.go
More file actions
151 lines (136 loc) · 3.99 KB
/
main.go
File metadata and controls
151 lines (136 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"flag"
"fmt"
"io/fs"
"os"
"runtime/pprof"
"github.com/charlievieth/fastwalk"
)
// GitVersion is set by the Makefile and contains the version string.
var GitVersion = ""
var args struct {
remove bool
recursive bool
q bool
qq bool
dryrun bool
fix bool
cpuprofile string
jobs int
}
// walkFn is used when `cshatag` is called with the `--recursive` option. It is the function called
// for each file or directory visited whilst traversing the file tree.
func walkFn(path string, info fs.DirEntry, err error) error {
if err != nil {
fmt.Fprintf(os.Stderr, "Error accessing %q: %v\n", path, err)
stats.errorsOpening.Add(1)
} else if info.Type().IsRegular() {
checkFile(path)
} else if !info.IsDir() {
if !args.qq {
fmt.Printf("<nonregular> %s\n", path)
}
}
return nil
}
// processArg is called for each command-line argument given. For regular files it will call
// `checkFile`. Directories will be processed recursively provided the `--recursive` flag is set.
// Symbolic links are not followed.
func processArg(fn string) {
fi, err := os.Lstat(fn) // Using Lstat to be consistent with filepath.Walk for symbolic links.
if err != nil {
fmt.Fprintln(os.Stderr, err)
stats.errorsOpening.Add(1)
} else if fi.Mode().IsRegular() {
checkFile(fn)
} else if fi.IsDir() {
if args.recursive {
config := fastwalk.Config{
NumWorkers: args.jobs,
Sort: fastwalk.SortLexical,
}
fastwalk.Walk(&config, fn, walkFn)
} else {
fmt.Fprintf(os.Stderr, "Error: %q is a directory, did you mean to use the '-recursive' option?\n", fn)
stats.errorsNotRegular.Add(1)
}
} else {
fmt.Fprintf(os.Stderr, "Error: %q is not a regular file.\n", fn)
stats.errorsNotRegular.Add(1)
}
}
func main() {
// the _main wrapper exists so deferred functions can run
// before os.Exit is called.
os.Exit(_main())
}
func _main() int {
const myname = "cshatag"
if GitVersion == "" {
GitVersion = "(version unknown)"
}
flag.BoolVar(&args.remove, "remove", false, "Remove any previously stored extended attributes.")
flag.BoolVar(&args.q, "q", false, "quiet: don't print <ok> files")
flag.BoolVar(&args.qq, "qq", false, "quiet²: Only print <corrupt> files and errors")
flag.BoolVar(&args.recursive, "recursive", false, "Recursively descend into subdirectories. "+
"Symbolic links are not followed.")
flag.BoolVar(&args.dryrun, "dry-run", false, "don't make any changes")
flag.BoolVar(&args.fix, "fix", false, "fix the stored sha256 on corrupt files")
flag.StringVar(&args.cpuprofile, "cpuprofile", "", "save cpu profile to specified file")
flag.IntVar(&args.jobs, "j", 0, "Number of threads to use. Default: auto")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s %s\n", myname, GitVersion)
fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] FILE [FILE2 ...]\n", myname)
fmt.Fprintf(os.Stderr, "Options:\n")
flag.PrintDefaults()
os.Exit(1)
}
flag.Parse()
if flag.NArg() == 0 {
flag.Usage()
}
if args.qq {
// quiet2 implies quiet
args.q = true
}
if args.cpuprofile != "" {
f, err := os.Create(args.cpuprofile)
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal: %v\n", err)
os.Exit(1)
}
err = pprof.StartCPUProfile(f)
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal: %v\n", err)
os.Exit(1)
}
defer pprof.StopCPUProfile()
}
for _, fn := range flag.Args() {
processArg(fn)
}
if stats.decisions.corrupt.Load() > 0 {
return 5
}
totalErrors := stats.errorsOpening.Load() + stats.errorsNotRegular.Load() + stats.errorsWritingXattr.Load() +
stats.errorsOther.Load()
if totalErrors > 0 {
if stats.errorsOpening.Load() == totalErrors {
return 2
} else if stats.errorsNotRegular.Load() == totalErrors {
return 3
} else if stats.errorsWritingXattr.Load() == totalErrors {
return 4
}
return 6
}
if stats.decisions.ok.Load()+
stats.decisions.outdated.Load()+
stats.decisions.timechange.Load()+
stats.decisions.new.Load()+
stats.removed.Load() == stats.total.Load() {
return 0
}
return 6
}