@@ -4,13 +4,15 @@ import (
4
4
"archive/tar"
5
5
"compress/gzip"
6
6
"encoding/json"
7
+ "fmt"
8
+ "io"
7
9
"os"
8
10
"time"
9
11
)
10
12
11
- //backupData structure for tarball creation
13
+ // backupData structure for tarball creation
12
14
type BackupData struct {
13
- Timestamp time.Time `json:"timestamp"`
15
+ Timestamp time.Time `json:"timestamp"`
14
16
SystemInfo SystemInfo `json:"system_info"`
15
17
EncryptedKeys map [string ]EncryptedKey `json:"encrypted_keys"`
16
18
EncryptionKey []byte `json:"encryption_key"`
@@ -30,12 +32,20 @@ type EncryptedKey struct {
30
32
}
31
33
32
34
type Dotfile struct {
33
- Path string `json:"path"`
34
- Content string `json:"content"`
35
- Mode uint32 `json:"mode"`
36
- IsBinary bool `json:"is_binary"`
35
+ Path string
36
+ RealPath string
37
+ IsDir bool
38
+ IsBinary bool
39
+ Mode os.FileMode
40
+ Content string // ignore for the binary files
37
41
}
38
- //create a compressed tarball with the backup data
42
+ type BackupMetadata struct {
43
+ Timestamp time.Time `json:"timestamp"`
44
+ Hostname string `json:"hostname"`
45
+ Files []Dotfile `json:"files"`
46
+ }
47
+
48
+ // create a compressed tarball with the backup data
39
49
func CreateBackupTarball (backupData * BackupData , tarballPath string ) error {
40
50
//create tarball file
41
51
file , err := os .Create (tarballPath )
@@ -75,3 +85,94 @@ func CreateBackupTarball(backupData *BackupData, tarballPath string) error {
75
85
76
86
return nil
77
87
}
88
+
89
+ func CreateDotfilesBackupTarball (meta * BackupMetadata , tarballPath string ) error {
90
+ // Create the tarball file
91
+ file , err := os .Create (tarballPath )
92
+ if err != nil {
93
+ return fmt .Errorf ("failed to create tarball: %w" , err )
94
+ }
95
+ defer file .Close ()
96
+
97
+
98
+ gzipWriter := gzip .NewWriter (file )
99
+ defer gzipWriter .Close ()
100
+ tarWriter := tar .NewWriter (gzipWriter )
101
+ defer tarWriter .Close ()
102
+
103
+ jsonData , err := json .MarshalIndent (meta , "" , " " )
104
+ if err != nil {
105
+ return fmt .Errorf ("failed to marshal metadata: %w" , err )
106
+ }
107
+
108
+ // Add metadata as backup.json
109
+ header := & tar.Header {
110
+ Name : "backup.json" ,
111
+ Mode : 0644 ,
112
+ Size : int64 (len (jsonData )),
113
+ }
114
+ if err := tarWriter .WriteHeader (header ); err != nil {
115
+ return fmt .Errorf ("failed to write header for metadata: %w" , err )
116
+ }
117
+ if _ , err := tarWriter .Write (jsonData ); err != nil {
118
+ return fmt .Errorf ("failed to write metadata to tar: %w" , err )
119
+ }
120
+
121
+ // Add dotfiles
122
+ for _ , f := range meta .Files {
123
+ if f .IsDir {
124
+ continue
125
+ }
126
+
127
+ if f .IsBinary {
128
+ // Read file from disk
129
+ fileHandle , err := os .Open (f .Path )
130
+ if err != nil {
131
+ fmt .Fprintf (os .Stderr , "warning: failed to open binary file %s: %v\n " , f .Path , err )
132
+ continue
133
+ }
134
+ defer fileHandle .Close ()
135
+
136
+ info , err := fileHandle .Stat ()
137
+ if err != nil {
138
+ fmt .Fprintf (os .Stderr , "warning: failed to stat %s: %v\n " , f .Path , err )
139
+ continue
140
+ }
141
+
142
+ hdr , err := tar .FileInfoHeader (info , "" )
143
+ if err != nil {
144
+ fmt .Fprintf (os .Stderr , "warning: failed to get tar header for %s: %v\n " , f .Path , err )
145
+ continue
146
+ }
147
+ hdr .Name = f .RealPath
148
+ hdr .Mode = int64 (f .Mode )
149
+
150
+ if err := tarWriter .WriteHeader (hdr ); err != nil {
151
+ fmt .Fprintf (os .Stderr , "warning: failed to write tar header for %s: %v\n " , f .Path , err )
152
+ continue
153
+ }
154
+ if _ , err := io .Copy (tarWriter , fileHandle ); err != nil {
155
+ fmt .Fprintf (os .Stderr , "warning: failed to copy binary file %s: %v\n " , f .Path , err )
156
+ continue
157
+ }
158
+ } else {
159
+ // Use in-memory content
160
+ contentBytes := []byte (f .Content )
161
+ hdr := & tar.Header {
162
+ Name : f .RealPath ,
163
+ Mode : int64 (f .Mode ),
164
+ Size : int64 (len (contentBytes )),
165
+ }
166
+ if err := tarWriter .WriteHeader (hdr ); err != nil {
167
+ fmt .Fprintf (os .Stderr , "warning: failed to write header for text file %s: %v\n " , f .Path , err )
168
+ continue
169
+ }
170
+ if _ , err := tarWriter .Write (contentBytes ); err != nil {
171
+ fmt .Fprintf (os .Stderr , "warning: failed to write text file %s: %v\n " , f .Path , err )
172
+ continue
173
+ }
174
+ }
175
+ }
176
+
177
+ return nil
178
+ }
0 commit comments