/
checksum.go
192 lines (163 loc) · 4.66 KB
/
checksum.go
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package main
import (
"bytes"
"crypto/md5"
"fmt"
"io/ioutil"
"os"
"os/exec"
fpath "path/filepath"
"strings"
"github.com/qaisjp/dmlivewiki/util"
"gopkg.in/urfave/cli.v1"
)
func performChecksum(c *cli.Context) {
fileInfo, filepath := util.CheckFilepathArgument(c)
if fileInfo == nil {
return
}
mode := "batch"
if c.GlobalBool("single") {
mode = "single"
}
fmt.Printf("The following filepath (%s mode) will be processed: %s\n", mode, filepath)
util.NotifyDeleteMode(c)
if !util.ShouldContinue(c) {
return
}
workingDirectory, err := os.Getwd()
if err != nil {
fmt.Println("could not get working directory for some reason")
fmt.Println("reason is: " + err.Error())
fmt.Println("aborting!")
return
}
if mode == "single" {
checksumProcessPath(filepath, fileInfo.Name(), c.GlobalBool("delete"), workingDirectory)
return
}
files, _ := ioutil.ReadDir(filepath)
for _, file := range files {
if file.IsDir() {
checksumProcessPath(fpath.Join(filepath, file.Name()), file.Name(), c.GlobalBool("delete"), workingDirectory)
}
}
}
func checksumProcessPath(directory string, name string, deleteMode bool, workingDirectory string) {
directory = fpath.Clean(directory)
baseFilename := fpath.Join(directory, name)
ffpFilename := baseFilename + ".ffp"
md5Filename := baseFilename + ".md5"
// If we're in delete mode, let's just delete the ffp and md5 files right away
if deleteMode {
util.RemoveFile(ffpFilename, true)
util.RemoveFile(md5Filename, true)
return
}
// Let's create an md5 file buffer and
// a pool to store files to be in the ffp
var md5Buffer bytes.Buffer
ffpPool := []string{
// The first arg for ffpPool is this
// because we're going to dump the entire
// pool in the command later
"--show-md5sum",
"--no-filename",
}
// This walks through every file in the folder
err := fpath.Walk(directory,
func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println("!!Encountered error for: " + path)
fmt.Println("!!This is the message: " + err.Error())
return nil
} else if info.IsDir() {
// We don't care about directories either,
// so let's jump out of here
return nil
}
if (path == ffpFilename) || (path == md5Filename) {
// ffpFilename is hashed afterwards
// and we don't need to hash ourself either
return nil
}
name := strings.TrimPrefix(
path,
directory+string(os.PathSeparator),
)
if fpath.Ext(path) == ".flac" {
// So if the file we have is an ffp file,
// lets add it to the pool to be checked!
ffpPool = append(ffpPool, name)
}
// Read the file
data, err := ioutil.ReadFile(path)
if err != nil {
fmt.Println("!!Encountered error for: " + path)
fmt.Println("!!This is the message: " + err.Error())
}
md5Buffer.WriteString(checksumFormatMD5(md5.Sum(data), strings.TrimPrefix(name, directory+"/")))
return nil
},
)
if err != nil {
fmt.Println("!!Error while walking through directory: " + directory)
fmt.Printf("!!Error: %s\n", err.Error())
}
// If the pool contains atleast one **filename**
// the first two items in the pool is actually just a flag!
if len(ffpPool) > 2 {
cmd := exec.Command(metaflacPath, ffpPool[:]...)
cmd.Dir = directory
data, err := cmd.Output()
if err != nil {
fmt.Println("metaflac returned an invalid response")
if data != nil {
fmt.Println(data)
}
panic(err)
}
hashes := strings.Split(string(data), "\n")
for i, hash := range hashes {
if (i == len(hashes)-1) && (hash == "") {
// Last line is an empty line
continue
}
hashes[i] = strings.TrimSpace(fmt.Sprintf("%s:%s", strings.TrimPrefix(ffpPool[i+2], directory), hash))
}
data = []byte(strings.Join(hashes, "\r\n"))
// The md5 buffer doesn't contain our ffp file, so let's write that to the buffer
md5Buffer.WriteString(checksumFormatMD5(md5.Sum(data), name+".ffp"))
// Let's write the ffp file now
ffp, err := os.Create(ffpFilename)
if err != nil {
fmt.Println("!!Could not create ffp file: " + ffpFilename)
fmt.Println("!!Error: " + err.Error())
} else {
defer ffp.Close()
_, err := ffp.Write(data)
if err != nil {
panic(err)
}
}
}
// If the md5buffer isn't empty
if md5Buffer.Len() > 0 {
// Let's write the md5 file
md5, err := os.Create(md5Filename)
if err != nil {
fmt.Println("!!Could not create md5 file: " + md5Filename)
fmt.Println("!!Error: " + err.Error())
} else {
defer md5.Close()
_, err := md5.Write(md5Buffer.Bytes())
if err != nil {
panic(err)
}
}
}
fmt.Println("Done with", directory)
}
func checksumFormatMD5(hash [16]byte, name string) string {
return fmt.Sprintf("%x *%s\r\n", hash, name)
}