-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathexport.go
86 lines (70 loc) · 1.84 KB
/
export.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
package fsdup
import (
"errors"
"os"
)
func Export(manifestId string, store ChunkStore, metaStore MetaStore, outputFile string) error {
manifest, err := metaStore.ReadManifest(manifestId)
if err != nil {
return err
}
if err := truncateExportFile(outputFile, manifest.Size()); err != nil {
return err
}
// Open file
out, err := os.OpenFile(outputFile, os.O_WRONLY, 0666)
if err != nil {
return err
}
buffer := make([]byte, manifest.chunkMaxSize)
offset := int64(0)
for _, breakpoint := range manifest.Offsets() {
part := manifest.Get(breakpoint)
sparse := part.checksum == nil
length := part.chunkto - part.chunkfrom
if sparse {
debugf("%013d Skipping sparse section of %d bytes\n", offset, length)
} else {
debugf("%013d Writing chunk %x, offset %d - %d (size %d)\n", offset, part.checksum, part.chunkfrom, part.chunkto, length)
read, err := store.ReadAt(part.checksum, buffer[:length], part.chunkfrom)
if err != nil {
return err
} else if int64(read) != length {
return errors.New("cannot read all required bytes from chunk")
}
written, err := out.WriteAt(buffer[:length], offset)
if err != nil {
return err
} else if int64(written) != length {
return errors.New("cannot write all bytes to output file")
}
}
offset += length
}
err = out.Close()
if err != nil {
return err
}
return nil
}
// truncateExportFile wipes the output file (truncate to zero, then to target size)
func truncateExportFile(outputFile string, size int64) error {
if _, err := os.Stat(outputFile); err != nil {
file, err := os.Create(outputFile)
if err != nil {
return err
}
err = file.Close()
if err != nil {
return err
}
} else {
if err := os.Truncate(outputFile, 0); err != nil {
return err
}
}
if err := os.Truncate(outputFile, size); err != nil {
return err
}
return nil
}