-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.go
127 lines (102 loc) · 2.74 KB
/
index.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
package fsdup
import (
"bytes"
"io"
"os"
"os/exec"
"strconv"
"strings"
)
type fileType int
const (
typeNtfs fileType = iota + 1
typeMbrDisk
typeGptDisk
typeUnknown
)
const (
probeTypeBufferLength = 1024
)
func Index(inputFile string, store ChunkStore, metaStore MetaStore, manifestId string, offset int64, exact bool,
noFile bool, minSize int64, chunkMaxSize int64, writeConcurrency int64) error {
file, err := os.Open(inputFile)
if err != nil {
return err
}
defer file.Close()
var chunker Chunker
size, err := readFileSize(file, inputFile)
if err != nil {
return err
}
// Probe type to figure out which chunker to pick
fileType, err := probeType(file, offset)
if err != nil {
return err
}
switch fileType {
case typeNtfs:
chunker = NewNtfsChunker(file, store, offset, exact, noFile, minSize, chunkMaxSize, writeConcurrency)
case typeMbrDisk:
chunker = NewMbrDiskChunker(file, store, offset, size, exact, noFile, minSize, chunkMaxSize, writeConcurrency)
case typeGptDisk:
chunker = NewGptDiskChunker(file, store, offset, size, exact, noFile, minSize, chunkMaxSize, writeConcurrency)
default:
chunker = NewFixedChunker(file, store, offset, size, chunkMaxSize, writeConcurrency)
}
manifest, err := chunker.Dedup()
if err != nil {
return err
}
if Debug {
debugf("Manifest:\n")
manifest.PrintDisk()
}
if err := metaStore.WriteManifest(manifestId, manifest); err != nil {
return err
}
return nil
}
// Determine file size for file or block device
func readFileSize(file *os.File, inputFile string) (int64, error) {
stat, err := file.Stat()
if err != nil {
return 0, err
}
if stat.Mode() & os.ModeDevice == os.ModeDevice {
// TODO This is ugly, but it works.
out, err := exec.Command("blockdev", "--getsize64", inputFile).Output()
if err != nil {
return 0, err
}
size, err := strconv.ParseInt(strings.Trim(string(out), "\n"), 10, 64)
if err != nil {
return 0, err
}
return size, nil
} else {
return stat.Size(), nil
}
}
func probeType(reader io.ReaderAt, offset int64) (fileType, error) {
buffer := make([]byte, probeTypeBufferLength)
_, err := reader.ReadAt(buffer, offset)
if err != nil {
return -1, err
}
// Be aware that the probing order is important.
// NTFS and GPT also have an MBR signature!
// Detect NTFS
if bytes.Compare([]byte(ntfsBootMagic), buffer[ntfsBootMagicOffset:ntfsBootMagicOffset+len(ntfsBootMagic)]) == 0 {
return typeNtfs, nil
}
// Detect GPT
if bytes.Compare([]byte(gptSignatureMagic), buffer[gptSignatureOffset:gptSignatureOffset+len(gptSignatureMagic)]) == 0 {
return typeGptDisk, nil
}
// Detect MBR
if mbrSignatureMagic == parseUintLE(buffer, mbrSignatureOffset, mbrSignatureLength) {
return typeMbrDisk, nil
}
return typeUnknown, nil
}