-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathreassemble.go
156 lines (134 loc) · 3.34 KB
/
reassemble.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
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
"strings"
)
var (
reassemblePath = flag.String("reassemble", "", "use this hot-clone backup file to restore into a file or block device")
reassembleOutput = flag.String("reassemble-output", "", "The path of the file or block device that is going to be restored to")
)
func reassembleMain() {
var imageFd *os.File
var err error
if *reassemblePath == "-" {
imageFd = os.Stdin
} else {
imageFd, err = os.Open(*reassemblePath)
if err != nil {
log.Fatalf("Can't open image file -reassemble %v -- %v", *reassembleOutput, err)
}
}
if *reassembleOutput == "" {
log.Fatalf("You must provide a -reassemble-output to restore to")
}
// First we should 100% check that we are dealing with a hot-clone image file
ReadBanner := ""
for {
b := make([]byte, 1)
n, err := imageFd.Read(b)
if err != nil {
if err == io.EOF {
break
}
log.Fatalf("Failed to read image banner %v", err)
}
if n == 1 {
ReadBanner += string(b)
}
if b[0] == '\n' {
break
}
}
if !strings.Contains(ReadBanner, "Hot-Clone") {
log.Fatalf("This image does not seem to be the output of hot-clone")
}
outputStat, err := os.Stat(*reassembleOutput)
if err != nil {
if !os.IsNotExist(err) {
log.Fatalf("Unable to stat output target %v", err)
}
}
var outputFD *os.File
if outputStat != nil {
if outputStat.Mode()&os.ModeDevice != 0 {
outputFD, err = os.OpenFile(*reassembleOutput, os.O_RDWR, 0777)
} else {
outputFD, err = os.Create(*reassembleOutput)
}
} else {
outputFD, err = os.Create(*reassembleOutput)
}
if err != nil {
log.Fatalf("Can't open/create output %v", err)
}
n := 0
for {
ReadHeader := ""
ReadEOF := false
for {
b := make([]byte, 1)
n, err := imageFd.Read(b)
if err != nil {
if err == io.EOF {
ReadEOF = true
break
}
log.Fatalf("Failed to read image header %v", err)
}
if n == 1 {
ReadHeader += string(b)
}
if b[0] == '\n' {
break
}
}
if ReadEOF {
break
}
SectorStart := 0
BytesLeftToRead := 0
parsed, err := fmt.Sscanf(ReadHeader, "S:%d\tL:%d\n", &SectorStart, &BytesLeftToRead)
if parsed != 2 {
log.Fatalf("Failed to parse header (%v) -- aborting (%v (%x) - %v - %v)", ReadHeader, ReadHeader, err, SectorStart, BytesLeftToRead)
}
_, err = outputFD.Seek(int64(SectorStart*512), 0)
if err != nil {
log.Fatalf("Seek failure (to %d) on output file/device %v", SectorStart, err)
}
if n == 0 || n%1000 == 0 {
if *debug {
log.Printf("Restoring section (Sector: %v (len %d bytes) (debug: '%s')", SectorStart, BytesLeftToRead, strings.Trim(ReadHeader, "\n"))
} else {
log.Printf("Restoring section (Sector: %v (len %d bytes)", SectorStart, BytesLeftToRead)
}
}
n++
var buf []byte
for {
expectedRead := 4096
if BytesLeftToRead < 4096 {
expectedRead = BytesLeftToRead
}
if BytesLeftToRead == 0 {
break
}
buf = make([]byte, expectedRead)
n, err := imageFd.Read(buf)
if err != nil {
log.Fatalf("Image read failure -- %v", err)
}
if n != expectedRead {
log.Printf("Image short read -- %v != %v (have %d bytes left)", n, expectedRead, BytesLeftToRead)
}
BytesLeftToRead = BytesLeftToRead - n
_, err = outputFD.Write(buf[:n])
if err != nil {
log.Fatalf("Output file/device write failure -- %v", err)
}
}
}
}