Skip to content

Commit 0958151

Browse files
author
Philipp Heckel
committed
Begin MBR parsing
1 parent de67557 commit 0958151

File tree

6 files changed

+127
-9
lines changed

6 files changed

+127
-9
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.idea
2+
build

Makefile

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
all:
1+
all: clean
2+
mkdir -p build
23
protoc --go_out=. internal/*.proto
3-
go build
4-
4+
go build -o build/fsdup
5+
6+
clean:
7+
rm -rf build

fsdup.go

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import (
66
"os"
77
)
88

9+
// TODO [HIGH] Support for MBR/GPT partition tables
10+
// TODO [HIGH] Support for any file
11+
// TODO [MED] Make manifest creation the last step (or part of all steps)
12+
// TODO [LOW] Sparsify all runs automatically
13+
914
func exit(code int, message string) {
1015
fmt.Println(message)
1116
os.Exit(code)

index.go

+109-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,38 @@
11
package main
22

33
import (
4+
"bytes"
45
"github.com/golang/protobuf/proto"
6+
"heckel.io/fsdup/internal"
7+
"io"
58
"io/ioutil"
69
"log"
710
"os"
811
)
912

13+
type fileType int
14+
15+
const (
16+
typeNtfs fileType = iota + 1
17+
typeMbrDisk
18+
typeUnknown
19+
)
20+
21+
const (
22+
probeTypeBufferLength = 512
23+
24+
mbrLength = 512
25+
mbrSectorSize = 512
26+
mbrSignatureOffset = 510
27+
mbrSignatureLength = 2
28+
mbrSignatureMagic = 0xaa55 // 0x55aa as little endian
29+
mbrEntryCount = 4
30+
mbrEntryFirstOffset = 446
31+
mbrEntryLength = 16
32+
mbrFirstSectorRelativeOffset = 8
33+
mbrEntryFirstSectorRelativeLength = 4
34+
)
35+
1036
func index(inputFile string, manifestFile string, offset int64, nowrite bool, exact bool) error {
1137
file, err := os.Open(inputFile)
1238
if err != nil {
@@ -15,13 +41,20 @@ func index(inputFile string, manifestFile string, offset int64, nowrite bool, ex
1541

1642
defer file.Close()
1743

18-
// Determine file type (partition, NTFS, other)
19-
// ...
44+
manifest := &internal.ManifestV1{}
2045

21-
ntfs := NewNtfsDeduper(file, offset, nowrite, exact)
22-
manifest, err := ntfs.Dedup()
46+
fileType, err := probeType(file, offset)
2347
if err != nil {
24-
log.Fatalln("Failed to dedup:", err)
48+
return err
49+
}
50+
51+
switch fileType {
52+
case typeNtfs:
53+
manifest, err = indexNtfs(file, offset, nowrite, exact)
54+
case typeMbrDisk:
55+
manifest, err = indexMbrDisk(file, offset, nowrite, exact)
56+
default:
57+
manifest, err = indexOther(file, offset, nowrite)
2558
}
2659

2760
if debug {
@@ -38,4 +71,74 @@ func index(inputFile string, manifestFile string, offset int64, nowrite bool, ex
3871
}
3972

4073
return nil
41-
}
74+
}
75+
76+
77+
func probeType(reader io.ReaderAt, offset int64) (fileType, error) {
78+
buffer := make([]byte, probeTypeBufferLength)
79+
_, err := reader.ReadAt(buffer, offset)
80+
if err != nil {
81+
return -1, err
82+
}
83+
84+
// Detect NTFS (note: this also has an MBR signature!)
85+
if bytes.Compare([]byte(ntfsBootMagic), buffer[ntfsBootMagicOffset:ntfsBootMagicOffset+len(ntfsBootMagic)]) == 0 {
86+
return typeNtfs, nil
87+
}
88+
89+
// Detect MBR
90+
if mbrSignatureMagic == parseUintLE(buffer, mbrSignatureOffset, mbrSignatureLength) {
91+
return typeMbrDisk, nil
92+
}
93+
94+
return typeUnknown, nil
95+
}
96+
97+
func indexMbrDisk(reader io.ReaderAt, offset int64, nowrite bool, exact bool) (*internal.ManifestV1, error) {
98+
println("i am a disk")
99+
100+
buffer := make([]byte, mbrLength)
101+
_, err := reader.ReadAt(buffer, offset)
102+
if err != nil {
103+
return nil, err
104+
}
105+
106+
for i := int64(0); i < mbrEntryCount; i++ {
107+
entryOffset := mbrEntryFirstOffset + i * mbrEntryLength
108+
109+
partitionFirstSector := parseUintLE(buffer, entryOffset+mbrFirstSectorRelativeOffset, mbrEntryFirstSectorRelativeLength)
110+
partitionOffset := offset + partitionFirstSector*mbrSectorSize
111+
Debugf("Reading MBR entry at %d, partition begins at sector %d, offset %d\n",
112+
entryOffset, partitionFirstSector, partitionOffset)
113+
114+
if partitionOffset == 0 {
115+
continue
116+
}
117+
118+
partitionType, err := probeType(reader, partitionOffset)
119+
if err != nil {
120+
continue
121+
}
122+
123+
if partitionType == typeNtfs {
124+
Debugf("NTFS partition found at offset %d\n", partitionOffset)
125+
return indexNtfs(reader, partitionOffset, nowrite, exact)
126+
}
127+
}
128+
129+
return nil, nil
130+
}
131+
132+
func indexNtfs(reader io.ReaderAt, offset int64, nowrite bool, exact bool) (*internal.ManifestV1, error) {
133+
ntfs := NewNtfsDeduper(reader, offset, nowrite, exact)
134+
manifest, err := ntfs.Dedup()
135+
if err != nil {
136+
return nil, err
137+
}
138+
139+
return manifest, nil
140+
}
141+
142+
func indexOther(file *os.File, offset int64, nowrite bool) (*internal.ManifestV1, error) {
143+
return nil, nil
144+
}

manifest.go

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import (
66
"io/ioutil"
77
)
88

9+
type diskManifest struct {
10+
11+
}
12+
913
func readManifestFromFile(manifestFile string) (*internal.ManifestV1, error) {
1014
in, err := ioutil.ReadFile(manifestFile)
1115
if err != nil {

partition.go

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
package main
2+

0 commit comments

Comments
 (0)