-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
227 lines (180 loc) · 4.24 KB
/
main.go
File metadata and controls
227 lines (180 loc) · 4.24 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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package main
import (
"crypto/md5"
"database/sql"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
_ "github.com/mattn/go-sqlite3"
)
const (
diskIndexDB = "./file-index.db"
breakPoint = 10000
)
var db *sql.DB
func main() {
//init
// os.Remove(diskIndexDB)
// os.Create("indexer.txt")
// os.Create("copy.txt")
bootDatabase()
// diskA := os.Args[1]
// diskB := os.Args[2]
dest := os.Args[3]
// getFilesFromFolder(true, diskA)
// getFilesFromFolder(false, diskB)
fmt.Println("--- FINISHED INDEXING ---")
fmt.Println("--- STARTING COPY ---")
files := findMissingFiles()
copyFiles(dest, files)
db.Close()
fmt.Println("--- FINISHED ---")
}
func bootDatabase() {
var err error
//We're going to store disk A information in a SQLite database
db, err = sql.Open("sqlite3", diskIndexDB)
if err != nil {
log.Fatal("Could not create the SQLite database", err)
}
// _, err = db.Exec(`
// CREATE TABLE file (
// id INTEGER PRIMARY KEY AUTOINCREMENT,
// origin BOOLEAN,
// hash VARCHAR(64),
// path VARCHAR(2048)
// );`)
// if err != nil {
// log.Fatal("DB-TABLE CREATE: fail ", err)
// }
}
func insertFile(origin bool, filePath string) {
//Not really sure what to do if there is an error, so let's log and quit to be safe. We don't want to mis files
stmt, err := db.Prepare("INSERT INTO file(origin, hash, path) VALUES (?,?,?)")
if err != nil {
redoLog("indexer", filePath)
return
}
md5, err := getMD5FromFile(filePath)
if err != nil {
redoLog("indexer", filePath)
return
}
_, err = stmt.Exec(origin, md5, filePath)
if err != nil {
redoLog("indexer", filePath)
return
}
}
func getFilesFromFolder(origin bool, searchDir string) {
fmt.Println("Indexing folder: " + searchDir)
var count int64 = 0
filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
if !f.IsDir() {
count++
if count%breakPoint == 0 {
fmt.Println(count)
}
insertFile(origin, path)
}
return nil
})
}
func getMD5FromFile(filePath string) (string, error) {
f, err := os.Open(filePath)
if err != nil {
return "", err
}
defer f.Close()
h := md5.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}
func findMissingFiles() []string {
//We left join to get the missing files and retrieve only the ones from the source
missingQuery := `
SELECT source.path,
destination.id AS missing
FROM FILE source
LEFT JOIN FILE destination
ON source.hash = destination.hash
AND source.origin = 1
AND destination.origin = 0
WHERE missing IS NULL
AND source.origin = 1`
rows, err := db.Query(missingQuery)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
files := []string{}
for rows.Next() {
var path string
var weDoNotCare interface{}
err = rows.Scan(&path, &weDoNotCare)
if err != nil {
log.Fatal(err)
}
files = append(files, path)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
return files
}
func copyFiles(dir string, files []string) {
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
log.Fatal("COPY INIT: Could not create copy-directory")
}
lengthFiles := len(files)
count := 0
for _, file := range files {
count++
percentage := int((count / lengthFiles) * 100)
if percentage%2 == 0 {
fmt.Println(fmt.Sprintf("%d%%", percentage))
}
err = copyFile(file, dir+strings.Replace(file, ":\\", "-", -1)) //Windows does not like ex. C:\ in the path as new folder, so hack it away
if err != nil {
redoLog("copy", file)
}
}
}
func copyFile(src string, dst string) (err error) {
//Create output dir
dir := filepath.Dir(dst)
os.MkdirAll(dir, os.ModePerm)
//Do the copy
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer func() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
if _, err = io.Copy(out, in); err != nil {
return err
}
return out.Sync()
}
//Dirty function to write the filepaths that crashedd to a file for after-processing
func redoLog(tag string, path string) {
f, _ := os.OpenFile(tag+".txt", os.O_APPEND|os.O_WRONLY, os.ModeAppend)
f.WriteString(path + "\r\n") //Window line endings, since we're running on that os for the backup
f.Close()
}