Repository navigation
Expand file tree
/
Copy pathutils.go
More file actions
177 lines (151 loc) · 3.45 KB
/
Copy pathutils.go
File metadata and controls
177 lines (151 loc) · 3.45 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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package main
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"os/signal"
"runtime"
"strings"
"sync/atomic"
"syscall"
"time"
)
var (
newlineSeparator = []byte{'\n'}
errWordlistCountCancelled = errors.New("wordlist line count cancelled")
)
func closeStopChannel(stopChan chan struct{}) {
select {
case <-stopChan:
// channel already closed, do nothing
default:
close(stopChan)
}
}
// ctrl+c
func handleGracefulShutdown(stopChan chan struct{}) {
interruptChan := make(chan os.Signal, 1)
signal.Notify(interruptChan, os.Interrupt, syscall.SIGTERM)
go func() {
<-interruptChan
fmt.Fprintln(os.Stderr, "\nCtrl+C pressed. Shutting down...")
closeStopChannel(stopChan)
}()
}
func setNumThreads(userThreads int) int {
if userThreads <= 0 || userThreads > runtime.NumCPU() {
return runtime.NumCPU()
}
return userThreads
}
func isAllHashesCracked(hashes []YescryptHash) bool {
for i := range hashes {
if atomic.LoadInt32(&hashes[i].Cracked) == 0 {
return false
}
}
return true
}
func normalizeGPUArgs(args []string) []string {
if len(args) <= 1 {
return args
}
out := make([]string, 0, len(args))
out = append(out, args[0])
for i := 1; i < len(args); i++ {
arg := args[i]
if arg != "-gpu" && arg != "--gpu" {
out = append(out, arg)
continue
}
value := "all"
if i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") {
value = args[i+1]
i++
}
out = append(out, "-gpu="+value)
}
return out
}
func countWordlistLines(path string) (uint64, error) {
return countWordlistLinesStop(path, nil)
}
func countWordlistLinesStop(path string, stopChan <-chan struct{}) (uint64, error) {
file, err := os.Open(path)
if err != nil {
return 0, err
}
defer file.Close()
// 16 MiB keeps syscall overhead small without consuming excessive RAM
buf := make([]byte, 16*1024*1024)
var lines uint64
var last byte
var readAny bool
for {
select {
case <-stopChan:
return 0, errWordlistCountCancelled
default:
}
n, err := file.Read(buf)
if n > 0 {
readAny = true
lines += uint64(bytes.Count(buf[:n], newlineSeparator))
last = buf[n-1]
}
if err == io.EOF {
break
}
if err != nil {
return 0, err
}
}
if readAny && last != '\n' {
lines++
}
return lines, nil
}
func formatDuration(d time.Duration) string {
return formatDurationMinutes(d, false)
}
func formatETADuration(d time.Duration) string {
return formatDurationMinutes(d, true)
}
func formatDurationMinutes(d time.Duration, roundUp bool) string {
if d < 0 {
d = 0
}
totalMinutes := uint64(d / time.Minute)
if roundUp && d%time.Minute != 0 {
totalMinutes++
}
days := totalMinutes / (24 * 60)
hours := (totalMinutes / 60) % 24
minutes := totalMinutes % 60
if days > 0 {
return fmt.Sprintf("%02dd:%02dh:%02dm", days, hours, minutes)
}
if hours > 0 {
return fmt.Sprintf("%02dh:%02dm", hours, minutes)
}
return fmt.Sprintf("%02dm", minutes)
}
func estimateRemainingDuration(linesProcessed, totalLines uint64, candidateRate float64) (time.Duration, bool) {
if linesProcessed >= totalLines {
return 0, true
}
if candidateRate <= 0 {
return 0, false
}
remaining := float64(totalLines-linesProcessed) / candidateRate
return time.Duration(remaining * float64(time.Second)), true
}
func estimateRemainingTime(linesProcessed, totalLines uint64, candidateRate float64) string {
remaining, ok := estimateRemainingDuration(linesProcessed, totalLines, candidateRate)
if !ok {
return "--"
}
return formatETADuration(remaining)
}