-
Notifications
You must be signed in to change notification settings - Fork 1
/
disk.go
128 lines (100 loc) · 3.54 KB
/
disk.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
package disk
import (
"fmt"
"io"
"os"
"github.com/CalebQ42/squashfs"
"github.com/gokrazy/tools/packer"
)
const mb = 1024 * 1024
const (
// MBRPartitionOffset is the offset where to find the MBR partition.
MBRPartitionOffset = 0
// BootPartitionOffset is the offset where to find the Boot partition.
BootPartitionOffset = 8192 * 512
// RootPartitionOffset is the offset where to find the first Root partition.
RootPartitionOffset = BootPartitionOffset + 100*mb
)
// PartsToFull merges multi parts (mbr, boot, root) image files of a disk into a single disk image file.
func PartsToFull(mbrSourcePath, bootSourcePath, rootSourcePath, destPath string) error {
// TODO: make this a mandatory flag for parts and gaf.
var targetStorageBytes = 2147483648
hostname, err := getHostname(rootSourcePath)
if err != nil {
return fmt.Errorf("error getting hostname from root file: %w", err)
}
p := packer.NewPackForHost(hostname)
// TODO: read these from the source imgs if possible
p.UsePartuuid = true
p.UseGPTPartuuid = true
p.UseGPT = true
f, err := os.Create(destPath)
if err != nil {
return fmt.Errorf("error creating destination disk file %s: %w", destPath, err)
}
if err := f.Truncate(int64(targetStorageBytes)); err != nil {
return fmt.Errorf("error preparing disk file: %w", err)
}
if err := p.Partition(f, uint64(targetStorageBytes)); err != nil {
return fmt.Errorf("error partitioning disk file: %w", err)
}
if _, err := f.Seek(BootPartitionOffset, io.SeekStart); err != nil {
return fmt.Errorf("error seeking disk boot partition start: %w", err)
}
bootFile, err := os.Open(bootSourcePath)
if err != nil {
return fmt.Errorf("error opening boot partition file %s: %w", bootSourcePath, err)
}
if _, err := io.Copy(f, bootFile); err != nil {
return fmt.Errorf("error writing boot partition to disk file: %w", err)
}
if _, err := f.Seek(MBRPartitionOffset, io.SeekStart); err != nil {
return fmt.Errorf("error seeking mbr partition start: %w", err)
}
mbrFile, err := os.Open(mbrSourcePath)
if err != nil {
return fmt.Errorf("error opening mbr partition file %s: %w", mbrSourcePath, err)
}
if _, err := io.Copy(f, mbrFile); err != nil {
return fmt.Errorf("error writing mbr partition to disk file: %w", err)
}
if _, err := f.Seek(RootPartitionOffset, io.SeekStart); err != nil {
return fmt.Errorf("error seeking disk file: %w", err)
}
tmp, err := os.CreateTemp("", "gokr-packer")
if err != nil {
return fmt.Errorf("error creating temporary file: %w", err)
}
defer os.Remove(tmp.Name())
defer tmp.Close()
rootFile, err := os.Open(rootSourcePath)
if err != nil {
return fmt.Errorf("error opening root partition file %s: %w", rootSourcePath, err)
}
if _, err := io.Copy(f, rootFile); err != nil {
return fmt.Errorf("error writing root partition to disk file: %w", err)
}
if _, err := tmp.Seek(0, io.SeekStart); err != nil {
return fmt.Errorf("error seeking temporary file: %w", err)
}
if _, err := io.Copy(f, tmp); err != nil {
return fmt.Errorf("error writing temporary file to disk file: %w", err)
}
return nil
}
func getHostname(rootSourcePath string) (string, error) {
f, err := os.Open(rootSourcePath)
if err != nil {
return "", fmt.Errorf("error opening root file: %w", err)
}
rd, err := squashfs.NewReader(f)
if err != nil {
return "", fmt.Errorf("error reading root file squashFS: %w", err)
}
hostnamePath := "etc/hostname"
b, err := rd.ReadFile(hostnamePath)
if err != nil {
return "", fmt.Errorf("error opening root squashFS hostname file %q: %w", hostnamePath, err)
}
return string(b), nil
}