-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathvss_windows.go
171 lines (135 loc) · 5 KB
/
vss_windows.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//go:build windows
// +build windows
package vss
import (
"fmt"
"github.com/go-ole/go-ole"
)
type Snapshotter struct{}
func (v *Snapshotter) CreateSnapshot(drive string, timeout int, force bool) (*Snapshot, error) {
successful := false
if timeout < 180 {
timeout = 180
}
// Initalize COM Library
ole.CoInitialize(0)
defer ole.CoUninitialize()
vssBackupComponent, err := LoadAndInitVSS()
if err != nil {
return nil, err
}
if err := vssBackupComponent.SetContext(VSS_CTX_BACKUP); err != nil {
vssBackupComponent.Release()
return nil, err
}
if err := vssBackupComponent.SetBackupState(VSS_BT_COPY); err != nil {
return nil, err
}
var async *IVssAsync
if async, err = vssBackupComponent.GatherWriterMetadata(); err != nil {
return nil, fmt.Errorf("VSS_GATHER - Shadow copy creation failed: GatherWriterMetadata, err: %s", err)
} else if async == nil {
return nil, fmt.Errorf("VSS_GATHER - Shadow copy creation failed: GatherWriterMetadata failed to return a valid IVssAsync object")
}
if err := async.Wait(timeout); err != nil {
return nil, fmt.Errorf("VSS_GATHER - Shadow copy creation failed: GatherWriterMetadata didn't finish properly, err: %s", err)
}
async.Release()
if isSupported, err := vssBackupComponent.IsVolumeSupported(drive); err != nil {
vssBackupComponent.Release()
return nil, fmt.Errorf("Snapshots are not supported for drive %s, err: %s", drive, err)
} else if !isSupported {
vssBackupComponent.Release()
return nil, fmt.Errorf("Snapshots are not supported for drive %s, err: %s", drive, err)
}
var snapshotSetID ole.GUID
var snapshotID ole.GUID
if err = vssBackupComponent.StartSnapshotSet(&snapshotSetID); err != nil {
return nil, fmt.Errorf("VSS_START - Shadow copy creation failed: StartSnapshotSet, err %s", err)
}
if err = vssBackupComponent.AddToSnapshotSet(drive, &snapshotID); err != nil {
return nil, fmt.Errorf("VSS_ADD - Shadow copy creation failed: AddToSnapshotSet, err: %s", err)
}
if async, err = vssBackupComponent.PrepareForBackup(); err != nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return nil, fmt.Errorf("VSS_PREPARE - Shadow copy creation failed: PrepareForBackup returned, err: %s", err)
}
if async == nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return nil, fmt.Errorf("VSS_PREPARE - Shadow copy creation failed: PrepareForBackup failed to return a valid IVssAsync object")
}
if err := async.Wait(timeout); err != nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return nil, fmt.Errorf("VSS_PREPARE - Shadow copy creation failed: PrepareForBackup didn't finish properly, err %s", err)
}
async.Release()
if async, err = vssBackupComponent.DoSnapshotSet(); err != nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return nil, fmt.Errorf("VSS_SNAPSHOT - Shadow copy creation failed: DoSnapshotSet, err: %s", err)
}
if async == nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return nil, fmt.Errorf("VSS_SNAPSHOT - Shadow copy creation failed: DoSnapshotSet failed to return a valid IVssAsync object")
}
if err := async.Wait(timeout); err != nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return nil, fmt.Errorf("VSS_SNAPSHOT - Shadow copy creation failed: DoSnapshotSet didn't finish properly, err: %s", err)
}
async.Release()
// Gather Properties
properties := VssSnapshotProperties{}
if err = vssBackupComponent.GetSnapshotProperties(snapshotID, &properties); err != nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return nil, fmt.Errorf("VSS_PROPERTIES - GetSnapshotProperties, err: %s", err)
}
details := SnapshotDetails{}
details, err = ParseProperties(properties)
snapshot := Snapshot{
Id: snapshotID.String(),
Details: details,
}
// Delete Snapshot if an error occurs
defer v.deleteOnFailure(&successful, snapshot.Id)
deviceObjectPath := snapshot.Details.DeviceObject + `\`
snapshot.DeviceObjectPath = deviceObjectPath
// Check Snapshot is Complete
if err := snapshot.Validate(); err != nil {
return nil, err
}
// Cancel sheduled deletion
successful = true
return &snapshot, nil
}
func (v *Snapshotter) DeleteSnapshot(snapshotId string) error {
// Initalize COM Library
ole.CoInitialize(0)
defer ole.CoUninitialize()
vssBackupComponent, err := LoadAndInitVSS()
if err != nil || vssBackupComponent == nil {
return err
}
defer vssBackupComponent.Release()
id := ole.NewGUID(snapshotId)
if deletedGUID, _, err := vssBackupComponent.DeleteSnapshots(*id); err != nil {
vssBackupComponent.AbortBackup()
vssBackupComponent.Release()
return fmt.Errorf("VSS_DELETE - Failed to delete the shadow copy: %s\n", deletedGUID.String())
}
return nil
}
func (v *Snapshotter) deleteOnFailure(finished *bool, snapshotId string) {
if *finished {
return
}
fmt.Printf("Early deleteing snapshot %s, due to error\n", snapshotId)
if err := v.DeleteSnapshot(snapshotId); err != nil {
fmt.Printf("error deleting corrupted snapshot %v:\n", err)
}
}