Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
libvirt
提交
4fab8d3f
L
libvirt
项目概览
openeuler
/
libvirt
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
libvirt
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
4fab8d3f
编写于
8月 11, 2014
作者:
T
Taowei
提交者:
Michal Privoznik
8月 15, 2014
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
vbox: Rewrite vboxDomainSnapshotDelete
上级
a9725126
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
637 addition
and
767 deletion
+637
-767
src/vbox/vbox_common.c
src/vbox/vbox_common.c
+609
-0
src/vbox/vbox_common.h
src/vbox/vbox_common.h
+13
-0
src/vbox/vbox_tmpl.c
src/vbox/vbox_tmpl.c
+11
-767
src/vbox/vbox_uniformed_api.h
src/vbox/vbox_uniformed_api.h
+4
-0
未找到文件。
src/vbox/vbox_common.c
浏览文件 @
4fab8d3f
...
...
@@ -6512,3 +6512,612 @@ int vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
vboxIIDUnalloc
(
&
domiid
);
return
ret
;
}
static
int
vboxDomainSnapshotDeleteSingle
(
vboxGlobalData
*
data
,
IConsole
*
console
,
ISnapshot
*
snapshot
)
{
IProgress
*
progress
=
NULL
;
vboxIIDUnion
iid
;
int
ret
=
-
1
;
nsresult
rc
;
resultCodeUnion
result
;
VBOX_IID_INITIALIZE
(
&
iid
);
rc
=
gVBoxAPI
.
UISnapshot
.
GetId
(
snapshot
,
&
iid
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get snapshot UUID"
));
goto
cleanup
;
}
rc
=
gVBoxAPI
.
UIConsole
.
DeleteSnapshot
(
console
,
&
iid
,
&
progress
);
if
(
NS_FAILED
(
rc
)
||
!
progress
)
{
if
(
rc
==
VBOX_E_INVALID_VM_STATE
)
{
virReportError
(
VIR_ERR_OPERATION_INVALID
,
"%s"
,
_
(
"cannot delete domain snapshot for running domain"
));
}
else
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not delete snapshot"
));
}
goto
cleanup
;
}
gVBoxAPI
.
UIProgress
.
WaitForCompletion
(
progress
,
-
1
);
gVBoxAPI
.
UIProgress
.
GetResultCode
(
progress
,
&
result
);
if
(
RC_FAILED
(
result
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not delete snapshot"
));
goto
cleanup
;
}
ret
=
0
;
cleanup:
VBOX_RELEASE
(
progress
);
vboxIIDUnalloc
(
&
iid
);
return
ret
;
}
static
int
vboxDomainSnapshotDeleteTree
(
vboxGlobalData
*
data
,
IConsole
*
console
,
ISnapshot
*
snapshot
)
{
vboxArray
children
=
VBOX_ARRAY_INITIALIZER
;
int
ret
=
-
1
;
nsresult
rc
;
size_t
i
;
rc
=
gVBoxAPI
.
UArray
.
vboxArrayGet
(
&
children
,
snapshot
,
gVBoxAPI
.
UArray
.
handleSnapshotGetChildren
(
snapshot
));
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get children snapshots"
));
goto
cleanup
;
}
for
(
i
=
0
;
i
<
children
.
count
;
i
++
)
{
if
(
vboxDomainSnapshotDeleteTree
(
data
,
console
,
children
.
items
[
i
]))
goto
cleanup
;
}
ret
=
vboxDomainSnapshotDeleteSingle
(
data
,
console
,
snapshot
);
cleanup:
gVBoxAPI
.
UArray
.
vboxArrayRelease
(
&
children
);
return
ret
;
}
static
int
vboxDomainSnapshotDeleteMetadataOnly
(
virDomainSnapshotPtr
snapshot
)
{
/*
* This function will remove the node in the vbox xml corresponding to the snapshot.
* It is usually called by vboxDomainSnapshotDelete() with the flag
* VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY.
* If you want to use it anywhere else, be careful, if the snapshot you want to delete
* has children, the result is not granted, they will probably will be deleted in the
* xml, but you may have a problem with hard drives.
*
* If the snapshot which is being deleted is the current one, we will set the current
* snapshot of the machine to the parent of this snapshot. Before writing the modified
* xml file, we undefine the machine from vbox. After writing the file, we redefine
* the machine with the new file.
*/
virDomainPtr
dom
=
snapshot
->
domain
;
VBOX_OBJECT_CHECK
(
dom
->
conn
,
int
,
-
1
);
virDomainSnapshotDefPtr
def
=
NULL
;
char
*
defXml
=
NULL
;
vboxIIDUnion
domiid
;
nsresult
rc
;
IMachine
*
machine
=
NULL
;
PRUnichar
*
settingsFilePathUtf16
=
NULL
;
char
*
settingsFilepath
=
NULL
;
virVBoxSnapshotConfMachinePtr
snapshotMachineDesc
=
NULL
;
int
isCurrent
=
-
1
;
int
it
=
0
;
PRUnichar
*
machineNameUtf16
=
NULL
;
char
*
machineName
=
NULL
;
char
*
nameTmpUse
=
NULL
;
char
*
machineLocationPath
=
NULL
;
PRUint32
aMediaSize
=
0
;
IMedium
**
aMedia
=
NULL
;
VBOX_IID_INITIALIZE
(
&
domiid
);
if
(
!
gVBoxAPI
.
vboxSnapshotRedefine
)
VIR_WARN
(
"This function may not work in current version"
);
defXml
=
vboxDomainSnapshotGetXMLDesc
(
snapshot
,
0
);
if
(
!
defXml
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get XML Desc of snapshot"
));
goto
cleanup
;
}
def
=
virDomainSnapshotDefParseString
(
defXml
,
data
->
caps
,
data
->
xmlopt
,
-
1
,
VIR_DOMAIN_SNAPSHOT_PARSE_DISKS
|
VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE
);
if
(
!
def
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get a virDomainSnapshotDefPtr"
));
goto
cleanup
;
}
if
(
openSessionForMachine
(
data
,
dom
->
uuid
,
&
domiid
,
&
machine
,
false
)
<
0
)
goto
cleanup
;
rc
=
gVBoxAPI
.
UIMachine
.
GetSettingsFilePath
(
machine
,
&
settingsFilePathUtf16
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot get settings file path"
));
goto
cleanup
;
}
VBOX_UTF16_TO_UTF8
(
settingsFilePathUtf16
,
&
settingsFilepath
);
/*Getting the machine name to retrieve the machine location path.*/
rc
=
gVBoxAPI
.
UIMachine
.
GetName
(
machine
,
&
machineNameUtf16
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot get machine name"
));
goto
cleanup
;
}
VBOX_UTF16_TO_UTF8
(
machineNameUtf16
,
&
machineName
);
if
(
virAsprintf
(
&
nameTmpUse
,
"%s.vbox"
,
machineName
)
<
0
)
goto
cleanup
;
machineLocationPath
=
virStringReplace
(
settingsFilepath
,
nameTmpUse
,
""
);
if
(
machineLocationPath
==
NULL
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get the machine location path"
));
goto
cleanup
;
}
snapshotMachineDesc
=
virVBoxSnapshotConfLoadVboxFile
(
settingsFilepath
,
machineLocationPath
);
if
(
!
snapshotMachineDesc
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot create a vboxSnapshotXmlPtr"
));
goto
cleanup
;
}
isCurrent
=
virVBoxSnapshotConfIsCurrentSnapshot
(
snapshotMachineDesc
,
def
->
name
);
if
(
isCurrent
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to know if the snapshot is the current snapshot"
));
goto
cleanup
;
}
if
(
isCurrent
)
{
/*
* If the snapshot is the current snapshot, it means that the machine has read-write
* disks. The first thing to do is to manipulate VirtualBox API to create
* differential read-write disks if the parent snapshot is not null.
*/
if
(
def
->
parent
!=
NULL
)
{
for
(
it
=
0
;
it
<
def
->
dom
->
ndisks
;
it
++
)
{
virVBoxSnapshotConfHardDiskPtr
readOnly
=
NULL
;
IMedium
*
medium
=
NULL
;
PRUnichar
*
locationUtf16
=
NULL
;
char
*
parentUuid
=
NULL
;
IMedium
*
newMedium
=
NULL
;
PRUnichar
*
formatUtf16
=
NULL
;
PRUnichar
*
newLocation
=
NULL
;
char
*
newLocationUtf8
=
NULL
;
IProgress
*
progress
=
NULL
;
virVBoxSnapshotConfHardDiskPtr
disk
=
NULL
;
char
*
uuid
=
NULL
;
char
*
format
=
NULL
;
char
**
searchResultTab
=
NULL
;
ssize_t
resultSize
=
0
;
char
*
tmp
=
NULL
;
vboxIIDUnion
iid
,
parentiid
;
resultCodeUnion
resultCode
;
VBOX_IID_INITIALIZE
(
&
iid
);
VBOX_IID_INITIALIZE
(
&
parentiid
);
readOnly
=
virVBoxSnapshotConfHardDiskPtrByLocation
(
snapshotMachineDesc
,
def
->
dom
->
disks
[
it
]
->
src
->
path
);
if
(
!
readOnly
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Cannot get hard disk by location"
));
goto
cleanup
;
}
if
(
readOnly
->
parent
==
NULL
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"The read only disk has no parent"
));
goto
cleanup
;
}
VBOX_UTF8_TO_UTF16
(
readOnly
->
parent
->
location
,
&
locationUtf16
);
rc
=
gVBoxAPI
.
UIVirtualBox
.
OpenMedium
(
data
->
vboxObj
,
locationUtf16
,
DeviceType_HardDisk
,
AccessMode_ReadWrite
,
&
medium
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to open HardDisk, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
rc
=
gVBoxAPI
.
UIMedium
.
GetId
(
medium
,
&
parentiid
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to get hardDisk Id, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
gVBoxAPI
.
UIID
.
vboxIIDToUtf8
(
data
,
&
parentiid
,
&
parentUuid
);
vboxIIDUnalloc
(
&
parentiid
);
VBOX_UTF16_FREE
(
locationUtf16
);
VBOX_UTF8_TO_UTF16
(
"VDI"
,
&
formatUtf16
);
if
(
virAsprintf
(
&
newLocationUtf8
,
"%sfakedisk-%s-%d.vdi"
,
machineLocationPath
,
def
->
parent
,
it
)
<
0
)
goto
cleanup
;
VBOX_UTF8_TO_UTF16
(
newLocationUtf8
,
&
newLocation
);
rc
=
gVBoxAPI
.
UIVirtualBox
.
CreateHardDiskMedium
(
data
->
vboxObj
,
formatUtf16
,
newLocation
,
&
newMedium
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to create HardDisk, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
VBOX_UTF16_FREE
(
formatUtf16
);
VBOX_UTF16_FREE
(
newLocation
);
PRUint32
tab
[
1
];
tab
[
0
]
=
MediumVariant_Diff
;
gVBoxAPI
.
UIMedium
.
CreateDiffStorage
(
medium
,
newMedium
,
1
,
tab
,
&
progress
);
gVBoxAPI
.
UIProgress
.
WaitForCompletion
(
progress
,
-
1
);
gVBoxAPI
.
UIProgress
.
GetResultCode
(
progress
,
&
resultCode
);
if
(
RC_FAILED
(
resultCode
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Error while creating diff storage, rc=%08x"
),
resultCode
.
uResultCode
);
goto
cleanup
;
}
VBOX_RELEASE
(
progress
);
/*
* The differential disk is created, we add it to the media registry and
* the machine storage controller.
*/
if
(
VIR_ALLOC
(
disk
)
<
0
)
goto
cleanup
;
rc
=
gVBoxAPI
.
UIMedium
.
GetId
(
newMedium
,
&
iid
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to get medium uuid, rc=%08x"
),
(
unsigned
)
rc
);
VIR_FREE
(
disk
);
goto
cleanup
;
}
gVBoxAPI
.
UIID
.
vboxIIDToUtf8
(
data
,
&
iid
,
&
uuid
);
disk
->
uuid
=
uuid
;
vboxIIDUnalloc
(
&
iid
);
if
(
VIR_STRDUP
(
disk
->
location
,
newLocationUtf8
)
<
0
)
{
VIR_FREE
(
disk
);
goto
cleanup
;
}
rc
=
gVBoxAPI
.
UIMedium
.
GetFormat
(
newMedium
,
&
formatUtf16
);
VBOX_UTF16_TO_UTF8
(
formatUtf16
,
&
format
);
disk
->
format
=
format
;
VBOX_UTF16_FREE
(
formatUtf16
);
if
(
virVBoxSnapshotConfAddHardDiskToMediaRegistry
(
disk
,
snapshotMachineDesc
->
mediaRegistry
,
parentUuid
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to add hard disk to the media registry"
));
goto
cleanup
;
}
/*Adding fake disks to the machine storage controllers*/
resultSize
=
virStringSearch
(
snapshotMachineDesc
->
storageController
,
VBOX_UUID_REGEX
,
it
+
1
,
&
searchResultTab
);
if
(
resultSize
!=
it
+
1
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID %s"
),
searchResultTab
[
it
]);
goto
cleanup
;
}
tmp
=
virStringReplace
(
snapshotMachineDesc
->
storageController
,
searchResultTab
[
it
],
disk
->
uuid
);
virStringFreeList
(
searchResultTab
);
VIR_FREE
(
snapshotMachineDesc
->
storageController
);
if
(
!
tmp
)
goto
cleanup
;
if
(
VIR_STRDUP
(
snapshotMachineDesc
->
storageController
,
tmp
)
<
0
)
goto
cleanup
;
VIR_FREE
(
tmp
);
/*Closing the "fake" disk*/
rc
=
gVBoxAPI
.
UIMedium
.
Close
(
newMedium
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to close the new medium, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
}
}
else
{
for
(
it
=
0
;
it
<
def
->
dom
->
ndisks
;
it
++
)
{
const
char
*
uuidRO
=
NULL
;
char
**
searchResultTab
=
NULL
;
ssize_t
resultSize
=
0
;
char
*
tmp
=
NULL
;
uuidRO
=
virVBoxSnapshotConfHardDiskUuidByLocation
(
snapshotMachineDesc
,
def
->
dom
->
disks
[
it
]
->
src
->
path
);
if
(
!
uuidRO
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"No such disk in media registry %s"
),
def
->
dom
->
disks
[
it
]
->
src
->
path
);
goto
cleanup
;
}
resultSize
=
virStringSearch
(
snapshotMachineDesc
->
storageController
,
VBOX_UUID_REGEX
,
it
+
1
,
&
searchResultTab
);
if
(
resultSize
!=
it
+
1
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID %s"
),
searchResultTab
[
it
]);
goto
cleanup
;
}
tmp
=
virStringReplace
(
snapshotMachineDesc
->
storageController
,
searchResultTab
[
it
],
uuidRO
);
virStringFreeList
(
searchResultTab
);
VIR_FREE
(
snapshotMachineDesc
->
storageController
);
if
(
!
tmp
)
goto
cleanup
;
if
(
VIR_STRDUP
(
snapshotMachineDesc
->
storageController
,
tmp
)
<
0
)
goto
cleanup
;
VIR_FREE
(
tmp
);
}
}
}
/*We remove the read write disks from the media registry*/
for
(
it
=
0
;
it
<
def
->
ndisks
;
it
++
)
{
const
char
*
uuidRW
=
virVBoxSnapshotConfHardDiskUuidByLocation
(
snapshotMachineDesc
,
def
->
disks
[
it
].
src
->
path
);
if
(
!
uuidRW
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID for location %s"
),
def
->
disks
[
it
].
src
->
path
);
goto
cleanup
;
}
if
(
virVBoxSnapshotConfRemoveHardDisk
(
snapshotMachineDesc
->
mediaRegistry
,
uuidRW
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to remove disk from media registry. uuid = %s"
),
uuidRW
);
goto
cleanup
;
}
}
/*If the parent snapshot is not NULL, we remove the-read only disks from the media registry*/
if
(
def
->
parent
!=
NULL
)
{
for
(
it
=
0
;
it
<
def
->
dom
->
ndisks
;
it
++
)
{
const
char
*
uuidRO
=
virVBoxSnapshotConfHardDiskUuidByLocation
(
snapshotMachineDesc
,
def
->
dom
->
disks
[
it
]
->
src
->
path
);
if
(
!
uuidRO
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID for location %s"
),
def
->
dom
->
disks
[
it
]
->
src
->
path
);
goto
cleanup
;
}
if
(
virVBoxSnapshotConfRemoveHardDisk
(
snapshotMachineDesc
->
mediaRegistry
,
uuidRO
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to remove disk from media registry. uuid = %s"
),
uuidRO
);
goto
cleanup
;
}
}
}
rc
=
gVBoxAPI
.
UIMachine
.
Unregister
(
machine
,
CleanupMode_DetachAllReturnHardDisksOnly
,
&
aMediaSize
,
&
aMedia
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to unregister machine, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
VBOX_RELEASE
(
machine
);
for
(
it
=
0
;
it
<
aMediaSize
;
it
++
)
{
IMedium
*
medium
=
aMedia
[
it
];
PRUnichar
*
locationUtf16
=
NULL
;
char
*
locationUtf8
=
NULL
;
if
(
!
medium
)
continue
;
rc
=
gVBoxAPI
.
UIMedium
.
GetLocation
(
medium
,
&
locationUtf16
);
VBOX_UTF16_TO_UTF8
(
locationUtf16
,
&
locationUtf8
);
if
(
isCurrent
&&
strstr
(
locationUtf8
,
"fake"
)
!=
NULL
)
{
/*we delete the fake disk because we don't need it anymore*/
IProgress
*
progress
=
NULL
;
resultCodeUnion
resultCode
;
rc
=
gVBoxAPI
.
UIMedium
.
DeleteStorage
(
medium
,
&
progress
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to delete medium, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
gVBoxAPI
.
UIProgress
.
WaitForCompletion
(
progress
,
-
1
);
gVBoxAPI
.
UIProgress
.
GetResultCode
(
progress
,
&
resultCode
);
if
(
RC_FAILED
(
resultCode
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Error while closing medium, rc=%08x"
),
resultCode
.
uResultCode
);
goto
cleanup
;
}
VBOX_RELEASE
(
progress
);
}
else
{
/* This a comment from vboxmanage code in the handleUnregisterVM
* function in VBoxManageMisc.cpp :
* Note that the IMachine::Unregister method will return the medium
* reference in a sane order, which means that closing will normally
* succeed, unless there is still another machine which uses the
* medium. No harm done if we ignore the error. */
rc
=
gVBoxAPI
.
UIMedium
.
Close
(
medium
);
}
VBOX_UTF16_FREE
(
locationUtf16
);
VBOX_UTF8_FREE
(
locationUtf8
);
}
/*removing the snapshot*/
if
(
virVBoxSnapshotConfRemoveSnapshot
(
snapshotMachineDesc
,
def
->
name
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to remove snapshot %s"
),
def
->
name
);
goto
cleanup
;
}
if
(
isCurrent
)
{
VIR_FREE
(
snapshotMachineDesc
->
currentSnapshot
);
if
(
def
->
parent
!=
NULL
)
{
virVBoxSnapshotConfSnapshotPtr
snap
=
virVBoxSnapshotConfSnapshotByName
(
snapshotMachineDesc
->
snapshot
,
def
->
parent
);
if
(
!
snap
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get the snapshot to remove"
));
goto
cleanup
;
}
if
(
VIR_STRDUP
(
snapshotMachineDesc
->
currentSnapshot
,
snap
->
uuid
)
<
0
)
goto
cleanup
;
}
}
/*Registering the machine*/
if
(
virVBoxSnapshotConfSaveVboxFile
(
snapshotMachineDesc
,
settingsFilepath
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to serialize the machine description"
));
goto
cleanup
;
}
rc
=
gVBoxAPI
.
UIVirtualBox
.
OpenMachine
(
data
->
vboxObj
,
settingsFilePathUtf16
,
&
machine
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to open Machine, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
rc
=
gVBoxAPI
.
UIVirtualBox
.
RegisterMachine
(
data
->
vboxObj
,
machine
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to register Machine, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
ret
=
0
;
cleanup:
VIR_FREE
(
def
);
VIR_FREE
(
defXml
);
VBOX_RELEASE
(
machine
);
VBOX_UTF16_FREE
(
settingsFilePathUtf16
);
VBOX_UTF8_FREE
(
settingsFilepath
);
VIR_FREE
(
snapshotMachineDesc
);
VBOX_UTF16_FREE
(
machineNameUtf16
);
VBOX_UTF8_FREE
(
machineName
);
VIR_FREE
(
machineLocationPath
);
VIR_FREE
(
nameTmpUse
);
return
ret
;
}
int
vboxDomainSnapshotDelete
(
virDomainSnapshotPtr
snapshot
,
unsigned
int
flags
)
{
virDomainPtr
dom
=
snapshot
->
domain
;
VBOX_OBJECT_CHECK
(
dom
->
conn
,
int
,
-
1
);
vboxIIDUnion
domiid
;
IMachine
*
machine
=
NULL
;
ISnapshot
*
snap
=
NULL
;
IConsole
*
console
=
NULL
;
PRUint32
state
;
nsresult
rc
;
vboxArray
snapChildren
=
VBOX_ARRAY_INITIALIZER
;
virCheckFlags
(
VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN
|
VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY
,
-
1
);
if
(
openSessionForMachine
(
data
,
dom
->
uuid
,
&
domiid
,
&
machine
,
false
)
<
0
)
goto
cleanup
;
snap
=
vboxDomainSnapshotGet
(
data
,
dom
,
machine
,
snapshot
->
name
);
if
(
!
snap
)
goto
cleanup
;
rc
=
gVBoxAPI
.
UIMachine
.
GetState
(
machine
,
&
state
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get domain state"
));
goto
cleanup
;
}
/* In case we just want to delete the metadata, we will edit the vbox file in order
*to remove the node concerning the snapshot
*/
if
(
flags
&
VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY
)
{
rc
=
gVBoxAPI
.
UArray
.
vboxArrayGet
(
&
snapChildren
,
snap
,
gVBoxAPI
.
UArray
.
handleSnapshotGetChildren
(
snap
));
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get snapshot children"
));
goto
cleanup
;
}
if
(
snapChildren
.
count
!=
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot delete metadata of a snapshot with children"
));
goto
cleanup
;
}
else
if
(
gVBoxAPI
.
vboxSnapshotRedefine
)
{
ret
=
vboxDomainSnapshotDeleteMetadataOnly
(
snapshot
);
}
goto
cleanup
;
}
if
(
gVBoxAPI
.
machineStateChecker
.
Online
(
state
))
{
virReportError
(
VIR_ERR_OPERATION_INVALID
,
"%s"
,
_
(
"cannot delete snapshots of running domain"
));
goto
cleanup
;
}
rc
=
gVBoxAPI
.
UISession
.
Open
(
data
,
&
domiid
,
machine
);
if
(
NS_SUCCEEDED
(
rc
))
rc
=
gVBoxAPI
.
UISession
.
GetConsole
(
data
->
vboxSession
,
&
console
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"could not open VirtualBox session with domain %s"
),
dom
->
name
);
goto
cleanup
;
}
if
(
flags
&
VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN
)
ret
=
vboxDomainSnapshotDeleteTree
(
data
,
console
,
snap
);
else
ret
=
vboxDomainSnapshotDeleteSingle
(
data
,
console
,
snap
);
cleanup:
VBOX_RELEASE
(
console
);
VBOX_RELEASE
(
snap
);
vboxIIDUnalloc
(
&
domiid
);
gVBoxAPI
.
UISession
.
Close
(
data
->
vboxSession
);
return
ret
;
}
src/vbox/vbox_common.h
浏览文件 @
4fab8d3f
...
...
@@ -265,6 +265,19 @@ enum MediumVariant
MediumVariant_Diff
=
0x20000
};
# define VBOX_E_OBJECT_NOT_FOUND 0x80BB0001
# define VBOX_E_INVALID_VM_STATE 0x80BB0002
# define VBOX_E_VM_ERROR 0x80BB0003
# define VBOX_E_FILE_ERROR 0x80BB0004
# define VBOX_E_IPRT_ERROR 0x80BB0005
# define VBOX_E_PDM_ERROR 0x80BB0006
# define VBOX_E_INVALID_OBJECT_STATE 0x80BB0007
# define VBOX_E_HOST_ERROR 0x80BB0008
# define VBOX_E_NOT_SUPPORTED 0x80BB0009
# define VBOX_E_XML_ERROR 0x80BB000A
# define VBOX_E_INVALID_SESSION_STATE 0x80BB000B
# define VBOX_E_OBJECT_IN_USE 0x80BB000C
/* Simplied definitions in vbox_CAPI_*.h */
typedef
void
const
*
PCVBOXXPCOM
;
...
...
src/vbox/vbox_tmpl.c
浏览文件 @
4fab8d3f
...
...
@@ -1383,146 +1383,6 @@ _vboxAttachDrivesOld(virDomainDefPtr def ATTRIBUTE_UNUSED,
#endif
/* VBOX_API_VERSION >= 4000000 */
static
int
vboxDomainSnapshotGetAll
(
virDomainPtr
dom
,
IMachine
*
machine
,
ISnapshot
***
snapshots
)
{
vboxIID
empty
=
VBOX_IID_INITIALIZER
;
ISnapshot
**
list
=
NULL
;
PRUint32
count
;
nsresult
rc
;
unsigned
int
next
;
unsigned
int
top
;
rc
=
machine
->
vtbl
->
GetSnapshotCount
(
machine
,
&
count
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"could not get snapshot count for domain %s"
),
dom
->
name
);
goto
error
;
}
if
(
count
==
0
)
goto
out
;
if
(
VIR_ALLOC_N
(
list
,
count
)
<
0
)
goto
error
;
#if VBOX_API_VERSION < 4000000
rc
=
machine
->
vtbl
->
GetSnapshot
(
machine
,
empty
.
value
,
list
);
#else
/* VBOX_API_VERSION >= 4000000 */
rc
=
machine
->
vtbl
->
FindSnapshot
(
machine
,
empty
.
value
,
list
);
#endif
/* VBOX_API_VERSION >= 4000000 */
if
(
NS_FAILED
(
rc
)
||
!
list
[
0
])
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"could not get root snapshot for domain %s"
),
dom
->
name
);
goto
error
;
}
/* BFS walk through snapshot tree */
top
=
1
;
for
(
next
=
0
;
next
<
count
;
next
++
)
{
vboxArray
children
=
VBOX_ARRAY_INITIALIZER
;
size_t
i
;
if
(
!
list
[
next
])
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"unexpected number of snapshots < %u"
),
count
);
goto
error
;
}
rc
=
vboxArrayGet
(
&
children
,
list
[
next
],
list
[
next
]
->
vtbl
->
GetChildren
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get children snapshots"
));
goto
error
;
}
for
(
i
=
0
;
i
<
children
.
count
;
i
++
)
{
ISnapshot
*
child
=
children
.
items
[
i
];
if
(
!
child
)
continue
;
if
(
top
==
count
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"unexpected number of snapshots > %u"
),
count
);
vboxArrayRelease
(
&
children
);
goto
error
;
}
VBOX_ADDREF
(
child
);
list
[
top
++
]
=
child
;
}
vboxArrayRelease
(
&
children
);
}
out:
*
snapshots
=
list
;
return
count
;
error:
if
(
list
)
{
for
(
next
=
0
;
next
<
count
;
next
++
)
VBOX_RELEASE
(
list
[
next
]);
}
VIR_FREE
(
list
);
return
-
1
;
}
static
ISnapshot
*
vboxDomainSnapshotGet
(
vboxGlobalData
*
data
,
virDomainPtr
dom
,
IMachine
*
machine
,
const
char
*
name
)
{
ISnapshot
**
snapshots
=
NULL
;
ISnapshot
*
snapshot
=
NULL
;
nsresult
rc
;
int
count
=
0
;
size_t
i
;
if
((
count
=
vboxDomainSnapshotGetAll
(
dom
,
machine
,
&
snapshots
))
<
0
)
goto
cleanup
;
for
(
i
=
0
;
i
<
count
;
i
++
)
{
PRUnichar
*
nameUtf16
;
char
*
nameUtf8
;
rc
=
snapshots
[
i
]
->
vtbl
->
GetName
(
snapshots
[
i
],
&
nameUtf16
);
if
(
NS_FAILED
(
rc
)
||
!
nameUtf16
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get snapshot name"
));
goto
cleanup
;
}
VBOX_UTF16_TO_UTF8
(
nameUtf16
,
&
nameUtf8
);
VBOX_UTF16_FREE
(
nameUtf16
);
if
(
STREQ
(
name
,
nameUtf8
))
snapshot
=
snapshots
[
i
];
VBOX_UTF8_FREE
(
nameUtf8
);
if
(
snapshot
)
break
;
}
if
(
!
snapshot
)
{
virReportError
(
VIR_ERR_OPERATION_INVALID
,
_
(
"domain %s has no snapshots with name %s"
),
dom
->
name
,
name
);
goto
cleanup
;
}
cleanup:
if
(
count
>
0
)
{
for
(
i
=
0
;
i
<
count
;
i
++
)
{
if
(
snapshots
[
i
]
!=
snapshot
)
VBOX_RELEASE
(
snapshots
[
i
]);
}
}
VIR_FREE
(
snapshots
);
return
snapshot
;
}
#if VBOX_API_VERSION < 3001000
static
int
_vboxDomainSnapshotRestore
(
virDomainPtr
dom
,
...
...
@@ -1630,633 +1490,6 @@ _vboxDomainSnapshotRestore(virDomainPtr dom,
}
#endif
static
int
vboxDomainSnapshotDeleteSingle
(
vboxGlobalData
*
data
,
IConsole
*
console
,
ISnapshot
*
snapshot
)
{
IProgress
*
progress
=
NULL
;
vboxIID
iid
=
VBOX_IID_INITIALIZER
;
int
ret
=
-
1
;
nsresult
rc
;
#if VBOX_API_VERSION == 2002000
nsresult
result
;
#else
PRInt32
result
;
#endif
rc
=
snapshot
->
vtbl
->
GetId
(
snapshot
,
&
iid
.
value
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get snapshot UUID"
));
goto
cleanup
;
}
#if VBOX_API_VERSION < 3001000
rc
=
console
->
vtbl
->
DiscardSnapshot
(
console
,
iid
.
value
,
&
progress
);
#else
rc
=
console
->
vtbl
->
DeleteSnapshot
(
console
,
iid
.
value
,
&
progress
);
#endif
if
(
NS_FAILED
(
rc
)
||
!
progress
)
{
if
(
rc
==
VBOX_E_INVALID_VM_STATE
)
{
virReportError
(
VIR_ERR_OPERATION_INVALID
,
"%s"
,
_
(
"cannot delete domain snapshot for running domain"
));
}
else
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not delete snapshot"
));
}
goto
cleanup
;
}
progress
->
vtbl
->
WaitForCompletion
(
progress
,
-
1
);
progress
->
vtbl
->
GetResultCode
(
progress
,
&
result
);
if
(
NS_FAILED
(
result
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not delete snapshot"
));
goto
cleanup
;
}
ret
=
0
;
cleanup:
VBOX_RELEASE
(
progress
);
vboxIIDUnalloc
(
&
iid
);
return
ret
;
}
static
int
vboxDomainSnapshotDeleteTree
(
vboxGlobalData
*
data
,
IConsole
*
console
,
ISnapshot
*
snapshot
)
{
vboxArray
children
=
VBOX_ARRAY_INITIALIZER
;
int
ret
=
-
1
;
nsresult
rc
;
size_t
i
;
rc
=
vboxArrayGet
(
&
children
,
snapshot
,
snapshot
->
vtbl
->
GetChildren
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get children snapshots"
));
goto
cleanup
;
}
for
(
i
=
0
;
i
<
children
.
count
;
i
++
)
{
if
(
vboxDomainSnapshotDeleteTree
(
data
,
console
,
children
.
items
[
i
]))
goto
cleanup
;
}
ret
=
vboxDomainSnapshotDeleteSingle
(
data
,
console
,
snapshot
);
cleanup:
vboxArrayRelease
(
&
children
);
return
ret
;
}
#if VBOX_API_VERSION >= 4002000
static
int
vboxDomainSnapshotDeleteMetadataOnly
(
virDomainSnapshotPtr
snapshot
)
{
/*
* This function will remove the node in the vbox xml corresponding to the snapshot.
* It is usually called by vboxDomainSnapshotDelete() with the flag
* VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY.
* If you want to use it anywhere else, be careful, if the snapshot you want to delete
* has children, the result is not granted, they will probably will be deleted in the
* xml, but you may have a problem with hard drives.
*
* If the snapshot which is being deleted is the current one, we will set the current
* snapshot of the machine to the parent of this snapshot. Before writing the modified
* xml file, we undefine the machine from vbox. After writing the file, we redefine
* the machine with the new file.
*/
virDomainPtr
dom
=
snapshot
->
domain
;
VBOX_OBJECT_CHECK
(
dom
->
conn
,
int
,
-
1
);
virDomainSnapshotDefPtr
def
=
NULL
;
char
*
defXml
=
NULL
;
vboxIID
domiid
=
VBOX_IID_INITIALIZER
;
nsresult
rc
;
IMachine
*
machine
=
NULL
;
PRUnichar
*
settingsFilePathUtf16
=
NULL
;
char
*
settingsFilepath
=
NULL
;
virVBoxSnapshotConfMachinePtr
snapshotMachineDesc
=
NULL
;
int
isCurrent
=
-
1
;
int
it
=
0
;
PRUnichar
*
machineNameUtf16
=
NULL
;
char
*
machineName
=
NULL
;
char
*
nameTmpUse
=
NULL
;
char
*
machineLocationPath
=
NULL
;
PRUint32
aMediaSize
=
0
;
IMedium
**
aMedia
=
NULL
;
defXml
=
vboxDomainSnapshotGetXMLDesc
(
snapshot
,
0
);
if
(
!
defXml
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get XML Desc of snapshot"
));
goto
cleanup
;
}
def
=
virDomainSnapshotDefParseString
(
defXml
,
data
->
caps
,
data
->
xmlopt
,
-
1
,
VIR_DOMAIN_SNAPSHOT_PARSE_DISKS
|
VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE
);
if
(
!
def
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get a virDomainSnapshotDefPtr"
));
goto
cleanup
;
}
vboxIIDFromUUID
(
&
domiid
,
dom
->
uuid
);
rc
=
VBOX_OBJECT_GET_MACHINE
(
domiid
.
value
,
&
machine
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_NO_DOMAIN
,
"%s"
,
_
(
"no domain with matching UUID"
));
goto
cleanup
;
}
rc
=
machine
->
vtbl
->
GetSettingsFilePath
(
machine
,
&
settingsFilePathUtf16
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot get settings file path"
));
goto
cleanup
;
}
VBOX_UTF16_TO_UTF8
(
settingsFilePathUtf16
,
&
settingsFilepath
);
/*Getting the machine name to retrieve the machine location path.*/
rc
=
machine
->
vtbl
->
GetName
(
machine
,
&
machineNameUtf16
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot get machine name"
));
goto
cleanup
;
}
VBOX_UTF16_TO_UTF8
(
machineNameUtf16
,
&
machineName
);
if
(
virAsprintf
(
&
nameTmpUse
,
"%s.vbox"
,
machineName
)
<
0
)
goto
cleanup
;
machineLocationPath
=
virStringReplace
(
settingsFilepath
,
nameTmpUse
,
""
);
if
(
machineLocationPath
==
NULL
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get the machine location path"
));
goto
cleanup
;
}
snapshotMachineDesc
=
virVBoxSnapshotConfLoadVboxFile
(
settingsFilepath
,
machineLocationPath
);
if
(
!
snapshotMachineDesc
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot create a vboxSnapshotXmlPtr"
));
goto
cleanup
;
}
isCurrent
=
virVBoxSnapshotConfIsCurrentSnapshot
(
snapshotMachineDesc
,
def
->
name
);
if
(
isCurrent
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to know if the snapshot is the current snapshot"
));
goto
cleanup
;
}
if
(
isCurrent
)
{
/*
* If the snapshot is the current snapshot, it means that the machine has read-write
* disks. The first thing to do is to manipulate VirtualBox API to create
* differential read-write disks if the parent snapshot is not null.
*/
if
(
def
->
parent
!=
NULL
)
{
for
(
it
=
0
;
it
<
def
->
dom
->
ndisks
;
it
++
)
{
virVBoxSnapshotConfHardDiskPtr
readOnly
=
NULL
;
IMedium
*
medium
=
NULL
;
PRUnichar
*
locationUtf16
=
NULL
;
PRUnichar
*
parentUuidUtf16
=
NULL
;
char
*
parentUuid
=
NULL
;
IMedium
*
newMedium
=
NULL
;
PRUnichar
*
formatUtf16
=
NULL
;
PRUnichar
*
newLocation
=
NULL
;
char
*
newLocationUtf8
=
NULL
;
IProgress
*
progress
=
NULL
;
PRInt32
resultCode
=
-
1
;
virVBoxSnapshotConfHardDiskPtr
disk
=
NULL
;
PRUnichar
*
uuidUtf16
=
NULL
;
char
*
uuid
=
NULL
;
char
*
format
=
NULL
;
char
**
searchResultTab
=
NULL
;
ssize_t
resultSize
=
0
;
char
*
tmp
=
NULL
;
readOnly
=
virVBoxSnapshotConfHardDiskPtrByLocation
(
snapshotMachineDesc
,
def
->
dom
->
disks
[
it
]
->
src
->
path
);
if
(
!
readOnly
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Cannot get hard disk by location"
));
goto
cleanup
;
}
if
(
readOnly
->
parent
==
NULL
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"The read only disk has no parent"
));
goto
cleanup
;
}
VBOX_UTF8_TO_UTF16
(
readOnly
->
parent
->
location
,
&
locationUtf16
);
rc
=
data
->
vboxObj
->
vtbl
->
OpenMedium
(
data
->
vboxObj
,
locationUtf16
,
DeviceType_HardDisk
,
AccessMode_ReadWrite
,
false
,
&
medium
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to open HardDisk, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
rc
=
medium
->
vtbl
->
GetId
(
medium
,
&
parentUuidUtf16
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to get hardDisk Id, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
VBOX_UTF16_TO_UTF8
(
parentUuidUtf16
,
&
parentUuid
);
VBOX_UTF16_FREE
(
parentUuidUtf16
);
VBOX_UTF16_FREE
(
locationUtf16
);
VBOX_UTF8_TO_UTF16
(
"VDI"
,
&
formatUtf16
);
if
(
virAsprintf
(
&
newLocationUtf8
,
"%sfakedisk-%s-%d.vdi"
,
machineLocationPath
,
def
->
parent
,
it
)
<
0
)
goto
cleanup
;
VBOX_UTF8_TO_UTF16
(
newLocationUtf8
,
&
newLocation
);
rc
=
data
->
vboxObj
->
vtbl
->
CreateHardDisk
(
data
->
vboxObj
,
formatUtf16
,
newLocation
,
&
newMedium
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to create HardDisk, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
VBOX_UTF16_FREE
(
formatUtf16
);
VBOX_UTF16_FREE
(
newLocation
);
# if VBOX_API_VERSION < 4003000
medium
->
vtbl
->
CreateDiffStorage
(
medium
,
newMedium
,
MediumVariant_Diff
,
&
progress
);
# else
PRUint32
tab
[
1
];
tab
[
0
]
=
MediumVariant_Diff
;
medium
->
vtbl
->
CreateDiffStorage
(
medium
,
newMedium
,
1
,
tab
,
&
progress
);
# endif
progress
->
vtbl
->
WaitForCompletion
(
progress
,
-
1
);
progress
->
vtbl
->
GetResultCode
(
progress
,
&
resultCode
);
if
(
NS_FAILED
(
resultCode
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Error while creating diff storage, rc=%08x"
),
(
unsigned
)
resultCode
);
goto
cleanup
;
}
VBOX_RELEASE
(
progress
);
/*
* The differential disk is created, we add it to the media registry and
* the machine storage controller.
*/
if
(
VIR_ALLOC
(
disk
)
<
0
)
goto
cleanup
;
rc
=
newMedium
->
vtbl
->
GetId
(
newMedium
,
&
uuidUtf16
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to get medium uuid, rc=%08x"
),
(
unsigned
)
rc
);
VIR_FREE
(
disk
);
goto
cleanup
;
}
VBOX_UTF16_TO_UTF8
(
uuidUtf16
,
&
uuid
);
disk
->
uuid
=
uuid
;
VBOX_UTF16_FREE
(
uuidUtf16
);
if
(
VIR_STRDUP
(
disk
->
location
,
newLocationUtf8
)
<
0
)
{
VIR_FREE
(
disk
);
goto
cleanup
;
}
rc
=
newMedium
->
vtbl
->
GetFormat
(
newMedium
,
&
formatUtf16
);
VBOX_UTF16_TO_UTF8
(
formatUtf16
,
&
format
);
disk
->
format
=
format
;
VBOX_UTF16_FREE
(
formatUtf16
);
if
(
virVBoxSnapshotConfAddHardDiskToMediaRegistry
(
disk
,
snapshotMachineDesc
->
mediaRegistry
,
parentUuid
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to add hard disk to the media registry"
));
goto
cleanup
;
}
/*Adding fake disks to the machine storage controllers*/
resultSize
=
virStringSearch
(
snapshotMachineDesc
->
storageController
,
VBOX_UUID_REGEX
,
it
+
1
,
&
searchResultTab
);
if
(
resultSize
!=
it
+
1
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID %s"
),
searchResultTab
[
it
]);
goto
cleanup
;
}
tmp
=
virStringReplace
(
snapshotMachineDesc
->
storageController
,
searchResultTab
[
it
],
disk
->
uuid
);
virStringFreeList
(
searchResultTab
);
VIR_FREE
(
snapshotMachineDesc
->
storageController
);
if
(
!
tmp
)
goto
cleanup
;
if
(
VIR_STRDUP
(
snapshotMachineDesc
->
storageController
,
tmp
)
<
0
)
goto
cleanup
;
VIR_FREE
(
tmp
);
/*Closing the "fake" disk*/
rc
=
newMedium
->
vtbl
->
Close
(
newMedium
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to close the new medium, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
}
}
else
{
for
(
it
=
0
;
it
<
def
->
dom
->
ndisks
;
it
++
)
{
const
char
*
uuidRO
=
NULL
;
char
**
searchResultTab
=
NULL
;
ssize_t
resultSize
=
0
;
char
*
tmp
=
NULL
;
uuidRO
=
virVBoxSnapshotConfHardDiskUuidByLocation
(
snapshotMachineDesc
,
def
->
dom
->
disks
[
it
]
->
src
->
path
);
if
(
!
uuidRO
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"No such disk in media registry %s"
),
def
->
dom
->
disks
[
it
]
->
src
->
path
);
goto
cleanup
;
}
resultSize
=
virStringSearch
(
snapshotMachineDesc
->
storageController
,
VBOX_UUID_REGEX
,
it
+
1
,
&
searchResultTab
);
if
(
resultSize
!=
it
+
1
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID %s"
),
searchResultTab
[
it
]);
goto
cleanup
;
}
tmp
=
virStringReplace
(
snapshotMachineDesc
->
storageController
,
searchResultTab
[
it
],
uuidRO
);
virStringFreeList
(
searchResultTab
);
VIR_FREE
(
snapshotMachineDesc
->
storageController
);
if
(
!
tmp
)
goto
cleanup
;
if
(
VIR_STRDUP
(
snapshotMachineDesc
->
storageController
,
tmp
)
<
0
)
goto
cleanup
;
VIR_FREE
(
tmp
);
}
}
}
/*We remove the read write disks from the media registry*/
for
(
it
=
0
;
it
<
def
->
ndisks
;
it
++
)
{
const
char
*
uuidRW
=
virVBoxSnapshotConfHardDiskUuidByLocation
(
snapshotMachineDesc
,
def
->
disks
[
it
].
src
->
path
);
if
(
!
uuidRW
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID for location %s"
),
def
->
disks
[
it
].
src
->
path
);
goto
cleanup
;
}
if
(
virVBoxSnapshotConfRemoveHardDisk
(
snapshotMachineDesc
->
mediaRegistry
,
uuidRW
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to remove disk from media registry. uuid = %s"
),
uuidRW
);
goto
cleanup
;
}
}
/*If the parent snapshot is not NULL, we remove the-read only disks from the media registry*/
if
(
def
->
parent
!=
NULL
)
{
for
(
it
=
0
;
it
<
def
->
dom
->
ndisks
;
it
++
)
{
const
char
*
uuidRO
=
virVBoxSnapshotConfHardDiskUuidByLocation
(
snapshotMachineDesc
,
def
->
dom
->
disks
[
it
]
->
src
->
path
);
if
(
!
uuidRO
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to find UUID for location %s"
),
def
->
dom
->
disks
[
it
]
->
src
->
path
);
goto
cleanup
;
}
if
(
virVBoxSnapshotConfRemoveHardDisk
(
snapshotMachineDesc
->
mediaRegistry
,
uuidRO
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to remove disk from media registry. uuid = %s"
),
uuidRO
);
goto
cleanup
;
}
}
}
rc
=
machine
->
vtbl
->
Unregister
(
machine
,
CleanupMode_DetachAllReturnHardDisksOnly
,
&
aMediaSize
,
&
aMedia
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to unregister machine, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
VBOX_RELEASE
(
machine
);
for
(
it
=
0
;
it
<
aMediaSize
;
it
++
)
{
IMedium
*
medium
=
aMedia
[
it
];
if
(
medium
)
{
PRUnichar
*
locationUtf16
=
NULL
;
char
*
locationUtf8
=
NULL
;
rc
=
medium
->
vtbl
->
GetLocation
(
medium
,
&
locationUtf16
);
VBOX_UTF16_TO_UTF8
(
locationUtf16
,
&
locationUtf8
);
if
(
isCurrent
&&
strstr
(
locationUtf8
,
"fake"
)
!=
NULL
)
{
/*we delete the fake disk because we don't need it anymore*/
IProgress
*
progress
=
NULL
;
PRInt32
resultCode
=
-
1
;
rc
=
medium
->
vtbl
->
DeleteStorage
(
medium
,
&
progress
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to delete medium, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
progress
->
vtbl
->
WaitForCompletion
(
progress
,
-
1
);
progress
->
vtbl
->
GetResultCode
(
progress
,
&
resultCode
);
if
(
NS_FAILED
(
resultCode
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Error while closing medium, rc=%08x"
),
(
unsigned
)
resultCode
);
goto
cleanup
;
}
VBOX_RELEASE
(
progress
);
}
else
{
/* This a comment from vboxmanage code in the handleUnregisterVM
* function in VBoxManageMisc.cpp :
* Note that the IMachine::Unregister method will return the medium
* reference in a sane order, which means that closing will normally
* succeed, unless there is still another machine which uses the
* medium. No harm done if we ignore the error. */
rc
=
medium
->
vtbl
->
Close
(
medium
);
}
VBOX_UTF16_FREE
(
locationUtf16
);
VBOX_UTF8_FREE
(
locationUtf8
);
}
}
/*removing the snapshot*/
if
(
virVBoxSnapshotConfRemoveSnapshot
(
snapshotMachineDesc
,
def
->
name
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to remove snapshot %s"
),
def
->
name
);
goto
cleanup
;
}
if
(
isCurrent
)
{
VIR_FREE
(
snapshotMachineDesc
->
currentSnapshot
);
if
(
def
->
parent
!=
NULL
)
{
virVBoxSnapshotConfSnapshotPtr
snap
=
virVBoxSnapshotConfSnapshotByName
(
snapshotMachineDesc
->
snapshot
,
def
->
parent
);
if
(
!
snap
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to get the snapshot to remove"
));
goto
cleanup
;
}
if
(
VIR_STRDUP
(
snapshotMachineDesc
->
currentSnapshot
,
snap
->
uuid
)
<
0
)
goto
cleanup
;
}
}
/*Registering the machine*/
if
(
virVBoxSnapshotConfSaveVboxFile
(
snapshotMachineDesc
,
settingsFilepath
)
<
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"Unable to serialize the machine description"
));
goto
cleanup
;
}
rc
=
data
->
vboxObj
->
vtbl
->
OpenMachine
(
data
->
vboxObj
,
settingsFilePathUtf16
,
&
machine
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to open Machine, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
rc
=
data
->
vboxObj
->
vtbl
->
RegisterMachine
(
data
->
vboxObj
,
machine
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"Unable to register Machine, rc=%08x"
),
(
unsigned
)
rc
);
goto
cleanup
;
}
ret
=
0
;
cleanup:
VIR_FREE
(
def
);
VIR_FREE
(
defXml
);
VBOX_RELEASE
(
machine
);
VBOX_UTF16_FREE
(
settingsFilePathUtf16
);
VBOX_UTF8_FREE
(
settingsFilepath
);
VIR_FREE
(
snapshotMachineDesc
);
VBOX_UTF16_FREE
(
machineNameUtf16
);
VBOX_UTF8_FREE
(
machineName
);
VIR_FREE
(
machineLocationPath
);
VIR_FREE
(
nameTmpUse
);
return
ret
;
}
#endif
static
int
vboxDomainSnapshotDelete
(
virDomainSnapshotPtr
snapshot
,
unsigned
int
flags
)
{
virDomainPtr
dom
=
snapshot
->
domain
;
VBOX_OBJECT_CHECK
(
dom
->
conn
,
int
,
-
1
);
vboxIID
domiid
=
VBOX_IID_INITIALIZER
;
IMachine
*
machine
=
NULL
;
ISnapshot
*
snap
=
NULL
;
IConsole
*
console
=
NULL
;
PRUint32
state
;
nsresult
rc
;
vboxArray
snapChildren
=
VBOX_ARRAY_INITIALIZER
;
virCheckFlags
(
VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN
|
VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY
,
-
1
);
vboxIIDFromUUID
(
&
domiid
,
dom
->
uuid
);
rc
=
VBOX_OBJECT_GET_MACHINE
(
domiid
.
value
,
&
machine
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_NO_DOMAIN
,
"%s"
,
_
(
"no domain with matching UUID"
));
goto
cleanup
;
}
snap
=
vboxDomainSnapshotGet
(
data
,
dom
,
machine
,
snapshot
->
name
);
if
(
!
snap
)
goto
cleanup
;
rc
=
machine
->
vtbl
->
GetState
(
machine
,
&
state
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get domain state"
));
goto
cleanup
;
}
/* In case we just want to delete the metadata, we will edit the vbox file in order
*to remove the node concerning the snapshot
*/
if
(
flags
&
VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY
)
{
rc
=
vboxArrayGet
(
&
snapChildren
,
snap
,
snap
->
vtbl
->
GetChildren
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"could not get snapshot children"
));
goto
cleanup
;
}
if
(
snapChildren
.
count
!=
0
)
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
"%s"
,
_
(
"cannot delete metadata of a snapshot with children"
));
goto
cleanup
;
}
else
{
#if VBOX_API_VERSION >= 4002000
ret
=
vboxDomainSnapshotDeleteMetadataOnly
(
snapshot
);
#endif
}
goto
cleanup
;
}
if
(
state
>=
MachineState_FirstOnline
&&
state
<=
MachineState_LastOnline
)
{
virReportError
(
VIR_ERR_OPERATION_INVALID
,
"%s"
,
_
(
"cannot delete snapshots of running domain"
));
goto
cleanup
;
}
rc
=
VBOX_SESSION_OPEN
(
domiid
.
value
,
machine
);
if
(
NS_SUCCEEDED
(
rc
))
rc
=
data
->
vboxSession
->
vtbl
->
GetConsole
(
data
->
vboxSession
,
&
console
);
if
(
NS_FAILED
(
rc
))
{
virReportError
(
VIR_ERR_INTERNAL_ERROR
,
_
(
"could not open VirtualBox session with domain %s"
),
dom
->
name
);
goto
cleanup
;
}
if
(
flags
&
VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN
)
ret
=
vboxDomainSnapshotDeleteTree
(
data
,
console
,
snap
);
else
ret
=
vboxDomainSnapshotDeleteSingle
(
data
,
console
,
snap
);
cleanup:
VBOX_RELEASE
(
console
);
VBOX_RELEASE
(
snap
);
vboxIIDUnalloc
(
&
domiid
);
VBOX_SESSION_CLOSE
();
return
ret
;
}
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
/* No Callback support for VirtualBox 2.2.* series */
/* No Callback support for VirtualBox 4.* series */
...
...
@@ -6231,6 +5464,16 @@ _consoleTakeSnapshot(IConsole *console, PRUnichar *name,
return
console
->
vtbl
->
TakeSnapshot
(
console
,
name
,
description
,
progress
);
}
static
nsresult
_consoleDeleteSnapshot
(
IConsole
*
console
,
vboxIIDUnion
*
iidu
,
IProgress
**
progress
)
{
#if VBOX_API_VERSION < 3001000
return
console
->
vtbl
->
DiscardSnapshot
(
console
,
IID_MEMBER
(
value
),
progress
);
#else
/* VBOX_API_VERSION >= 3001000 */
return
console
->
vtbl
->
DeleteSnapshot
(
console
,
IID_MEMBER
(
value
),
progress
);
#endif
/* VBOX_API_VERSION >= 3001000 */
}
static
nsresult
_progressWaitForCompletion
(
IProgress
*
progress
,
PRInt32
timeout
)
{
...
...
@@ -7243,6 +6486,7 @@ static vboxUniformedIConsole _UIConsole = {
.
PowerDown
=
_consolePowerDown
,
.
Reset
=
_consoleReset
,
.
TakeSnapshot
=
_consoleTakeSnapshot
,
.
DeleteSnapshot
=
_consoleDeleteSnapshot
,
};
static
vboxUniformedIProgress
_UIProgress
=
{
...
...
src/vbox/vbox_uniformed_api.h
浏览文件 @
4fab8d3f
...
...
@@ -272,6 +272,7 @@ typedef struct {
nsresult
(
*
Reset
)(
IConsole
*
console
);
nsresult
(
*
TakeSnapshot
)(
IConsole
*
console
,
PRUnichar
*
name
,
PRUnichar
*
description
,
IProgress
**
progress
);
nsresult
(
*
DeleteSnapshot
)(
IConsole
*
console
,
vboxIIDUnion
*
iidu
,
IProgress
**
progress
);
}
vboxUniformedIConsole
;
/* Functions for IProgress */
...
...
@@ -596,6 +597,9 @@ int vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
unsigned
int
flags
);
int
vboxDomainRevertToSnapshot
(
virDomainSnapshotPtr
snapshot
,
unsigned
int
flags
);
int
vboxDomainSnapshotDelete
(
virDomainSnapshotPtr
snapshot
,
unsigned
int
flags
);
/* Version specified functions for installing uniformed API */
void
vbox22InstallUniformedAPI
(
vboxUniformedAPI
*
pVBoxAPI
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录