VirtualBox

source: vbox/trunk/src/VBox/Main/SnapshotImpl.cpp@ 8971

Last change on this file since 8971 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "SnapshotImpl.h"
23
24#include "MachineImpl.h"
25#include "Logging.h"
26
27#include <iprt/path.h>
28#include <VBox/param.h>
29#include <VBox/err.h>
30
31#include <algorithm>
32
33// constructor / destructor
34////////////////////////////////////////////////////////////////////////////////
35
36Snapshot::Data::Data()
37{
38 RTTimeSpecSetMilli (&mTimeStamp, 0);
39};
40
41Snapshot::Data::~Data()
42{
43};
44
45HRESULT Snapshot::FinalConstruct()
46{
47 LogFlowMember (("Snapshot::FinalConstruct()\n"));
48 return S_OK;
49}
50
51void Snapshot::FinalRelease()
52{
53 LogFlowMember (("Snapshot::FinalRelease()\n"));
54 uninit();
55}
56
57/**
58 * Initializes the instance
59 *
60 * @param aId id of the snapshot
61 * @param aName name of the snapshot
62 * @param aDescription name of the snapshot (NULL if no description)
63 * @param aTimeStamp timestamp of the snapshot, in ms since 1970-01-01 UTC
64 * @param aMachine machine associated with this snapshot
65 * @param aParent parent snapshot (NULL if no parent)
66 */
67HRESULT Snapshot::init (const Guid &aId, INPTR BSTR aName, INPTR BSTR aDescription,
68 RTTIMESPEC aTimeStamp, SnapshotMachine *aMachine,
69 Snapshot *aParent)
70{
71 LogFlowMember (("Snapshot::init(aParent=%p)\n", aParent));
72
73 ComAssertRet (!aId.isEmpty() && aName && aMachine, E_INVALIDARG);
74
75 AutoWriteLock alock (this);
76 ComAssertRet (!isReady(), E_UNEXPECTED);
77
78 mParent = aParent;
79
80 mData.mId = aId;
81 mData.mName = aName;
82 mData.mDescription = aDescription;
83 mData.mTimeStamp = aTimeStamp;
84 mData.mMachine = aMachine;
85
86 if (aParent)
87 aParent->addDependentChild (this);
88
89 setReady (true);
90
91 return S_OK;
92}
93
94/**
95 * Uninitializes the instance and sets the ready flag to FALSE.
96 * Called either from FinalRelease(), by the parent when it gets destroyed,
97 * or by a third party when it decides this object is no more valid.
98 */
99void Snapshot::uninit()
100{
101 LogFlowMember (("Snapshot::uninit()\n"));
102
103 AutoWriteLock alock (this);
104
105 LogFlowMember (("Snapshot::uninit(): isReady=%d\n", isReady()));
106 if (!isReady())
107 return;
108
109 // uninit all children
110 uninitDependentChildren();
111
112 setReady (false);
113
114 if (mParent)
115 {
116 alock.leave();
117 mParent->removeDependentChild (this);
118 alock.enter();
119 mParent.setNull();
120 }
121
122 if (mData.mMachine)
123 {
124 mData.mMachine->uninit();
125 mData.mMachine.setNull();
126 }
127}
128
129/**
130 * Discards the current snapshot by removing it from the tree of snapshots
131 * and reparenting its children.
132 * This method also calls #uninit() in case of success.
133 */
134void Snapshot::discard()
135{
136 LogFlowMember (("Snapshot::discard()\n"));
137
138 AutoWriteLock alock (this);
139 AssertReturn (isReady(), (void) 0);
140
141 {
142 AutoWriteLock chLock (childrenLock ());
143 AssertReturn (!!mParent || children().size() <= 1, (void) 0);
144
145 for (SnapshotList::const_iterator it = children().begin();
146 it != children().end(); ++ it)
147 {
148 ComObjPtr <Snapshot> child = *it;
149 AutoWriteLock childLock (child);
150 // reparent the child
151 child->mParent = mParent;
152 if (mParent)
153 mParent->addDependentChild (child);
154 }
155 }
156
157 // detach all our children to avoid their uninit in #uninit()
158 removeDependentChildren();
159
160 // finalize uninitialization
161 uninit();
162}
163
164// ISnapshot methods
165////////////////////////////////////////////////////////////////////////////////
166
167STDMETHODIMP Snapshot::COMGETTER(Id) (GUIDPARAMOUT aId)
168{
169 if (!aId)
170 return E_POINTER;
171
172 AutoWriteLock alock (this);
173 CHECK_READY();
174
175 mData.mId.cloneTo (aId);
176 return S_OK;
177}
178
179STDMETHODIMP Snapshot::COMGETTER(Name) (BSTR *aName)
180{
181 if (!aName)
182 return E_POINTER;
183
184 AutoWriteLock alock (this);
185 CHECK_READY();
186
187 mData.mName.cloneTo (aName);
188 return S_OK;
189}
190
191/**
192 * @note Locks this object for writing, then calls Machine::onSnapshotChange()
193 * (see its lock requirements).
194 */
195STDMETHODIMP Snapshot::COMSETTER(Name) (INPTR BSTR aName)
196{
197 if (!aName)
198 return E_INVALIDARG;
199
200 AutoWriteLock alock (this);
201 CHECK_READY();
202
203 if (mData.mName != aName)
204 {
205 mData.mName = aName;
206
207 alock.leave(); /* Important! (child->parent locks are forbidden) */
208
209 return mData.mMachine->onSnapshotChange (this);
210 }
211
212 return S_OK;
213}
214
215STDMETHODIMP Snapshot::COMGETTER(Description) (BSTR *aDescription)
216{
217 if (!aDescription)
218 return E_POINTER;
219
220 AutoWriteLock alock (this);
221 CHECK_READY();
222
223 mData.mDescription.cloneTo (aDescription);
224 return S_OK;
225}
226
227STDMETHODIMP Snapshot::COMSETTER(Description) (INPTR BSTR aDescription)
228{
229 if (!aDescription)
230 return E_INVALIDARG;
231
232 AutoWriteLock alock (this);
233 CHECK_READY();
234
235 if (mData.mDescription != aDescription)
236 {
237 mData.mDescription = aDescription;
238
239 alock.leave(); /* Important! (child->parent locks are forbidden) */
240
241 return mData.mMachine->onSnapshotChange (this);
242 }
243
244 return S_OK;
245}
246
247STDMETHODIMP Snapshot::COMGETTER(TimeStamp) (LONG64 *aTimeStamp)
248{
249 if (!aTimeStamp)
250 return E_POINTER;
251
252 AutoWriteLock alock (this);
253 CHECK_READY();
254
255 *aTimeStamp = RTTimeSpecGetMilli (&mData.mTimeStamp);
256 return S_OK;
257}
258
259STDMETHODIMP Snapshot::COMGETTER(Online) (BOOL *aOnline)
260{
261 if (!aOnline)
262 return E_POINTER;
263
264 AutoWriteLock alock (this);
265 CHECK_READY();
266
267 *aOnline = !stateFilePath().isNull();
268 return S_OK;
269}
270
271STDMETHODIMP Snapshot::COMGETTER(Machine) (IMachine **aMachine)
272{
273 if (!aMachine)
274 return E_POINTER;
275
276 AutoWriteLock alock (this);
277 CHECK_READY();
278
279 mData.mMachine.queryInterfaceTo (aMachine);
280 return S_OK;
281}
282
283STDMETHODIMP Snapshot::COMGETTER(Parent) (ISnapshot **aParent)
284{
285 if (!aParent)
286 return E_POINTER;
287
288 AutoWriteLock alock (this);
289 CHECK_READY();
290
291 mParent.queryInterfaceTo (aParent);
292 return S_OK;
293}
294
295STDMETHODIMP Snapshot::COMGETTER(Children) (ISnapshotCollection **aChildren)
296{
297 if (!aChildren)
298 return E_POINTER;
299
300 AutoWriteLock alock (this);
301 CHECK_READY();
302
303 AutoWriteLock chLock (childrenLock ());
304
305 ComObjPtr <SnapshotCollection> collection;
306 collection.createObject();
307 collection->init (children());
308 collection.queryInterfaceTo (aChildren);
309
310 return S_OK;
311}
312
313// public methods only for internal purposes
314////////////////////////////////////////////////////////////////////////////////
315
316/**
317 * @note
318 * Must be called from under the object's lock!
319 */
320const Bstr &Snapshot::stateFilePath() const
321{
322 return mData.mMachine->mSSData->mStateFilePath;
323}
324
325/**
326 * Returns the number of children of this snapshot, including grand-children,
327 * etc.
328 */
329ULONG Snapshot::descendantCount()
330{
331 AutoWriteLock alock(this);
332 AssertReturn (isReady(), 0);
333
334 AutoWriteLock chLock (childrenLock ());
335
336 ULONG count = children().size();
337
338 for (SnapshotList::const_iterator it = children().begin();
339 it != children().end(); ++ it)
340 {
341 count += (*it)->descendantCount();
342 }
343
344 return count;
345}
346
347/**
348 * Searches for a snapshot with the given ID among children, grand-children,
349 * etc. of this snapshot. This snapshot itself is also included in the search.
350 */
351ComObjPtr <Snapshot> Snapshot::findChildOrSelf (INPTR GUIDPARAM aId)
352{
353 ComObjPtr <Snapshot> child;
354
355 AutoWriteLock alock (this);
356 AssertReturn (isReady(), child);
357
358 if (mData.mId == aId)
359 child = this;
360 else
361 {
362 AutoWriteLock chLock (childrenLock ());
363 for (SnapshotList::const_iterator it = children().begin();
364 !child && it != children().end(); ++ it)
365 {
366 child = (*it)->findChildOrSelf (aId);
367 }
368 }
369
370 return child;
371}
372
373/**
374 * Searches for a first snapshot with the given name among children,
375 * grand-children, etc. of this snapshot. This snapshot itself is also included
376 * in the search.
377 */
378ComObjPtr <Snapshot> Snapshot::findChildOrSelf (INPTR BSTR aName)
379{
380 ComObjPtr <Snapshot> child;
381 AssertReturn (aName, child);
382
383 AutoWriteLock alock (this);
384 AssertReturn (isReady(), child);
385
386 if (mData.mName == aName)
387 child = this;
388 else
389 {
390 AutoWriteLock chLock (childrenLock ());
391 for (SnapshotList::const_iterator it = children().begin();
392 !child && it != children().end(); ++ it)
393 {
394 child = (*it)->findChildOrSelf (aName);
395 }
396 }
397
398 return child;
399}
400
401/**
402 * Returns @c true if the given DVD image is attached to this snapshot or any
403 * of its children, recursively.
404 *
405 * @param aId Image ID to check.
406 *
407 * @note Locks this object for reading.
408 */
409bool Snapshot::isDVDImageUsed (const Guid &aId)
410{
411 AutoReadLock alock (this);
412 AssertReturn (isReady(), false);
413
414 AssertReturn (!mData.mMachine.isNull(), false);
415 AssertReturn (!mData.mMachine->mDVDDrive.isNull(), false);
416
417 DVDDrive::Data *d = mData.mMachine->mDVDDrive->data().data();
418
419 if (d &&
420 d->mDriveState == DriveState_ImageMounted)
421 {
422 Guid id;
423 HRESULT rc = d->mDVDImage->COMGETTER(Id) (id.asOutParam());
424 AssertComRC (rc);
425 if (id == aId)
426 return true;
427 }
428
429 AutoReadLock chLock (childrenLock());
430 for (SnapshotList::const_iterator it = children().begin();
431 it != children().end(); ++ it)
432 {
433 if ((*it)->isDVDImageUsed (aId))
434 return true;
435 }
436
437 return false;
438}
439
440/**
441 * Returns @c true if the given Floppy image is attached to this snapshot or any
442 * of its children, recursively.
443 *
444 * @param aId Image ID to check.
445 *
446 * @note Locks this object for reading.
447 */
448bool Snapshot::isFloppyImageUsed (const Guid &aId)
449{
450 AutoReadLock alock (this);
451 AssertReturn (isReady(), false);
452
453 AssertReturn (!mData.mMachine.isNull(), false);
454 AssertReturn (!mData.mMachine->mFloppyDrive.isNull(), false);
455
456 FloppyDrive::Data *d = mData.mMachine->mFloppyDrive->data().data();
457
458 if (d &&
459 d->mDriveState == DriveState_ImageMounted)
460 {
461 Guid id;
462 HRESULT rc = d->mFloppyImage->COMGETTER(Id) (id.asOutParam());
463 AssertComRC (rc);
464 if (id == aId)
465 return true;
466 }
467
468 AutoReadLock chLock (childrenLock());
469 for (SnapshotList::const_iterator it = children().begin();
470 it != children().end(); ++ it)
471 {
472 if ((*it)->isFloppyImageUsed (aId))
473 return true;
474 }
475
476 return false;
477}
478
479/**
480 * Checks if the specified path change affects the saved state file path of
481 * this snapshot or any of its (grand-)children and updates it accordingly.
482 *
483 * Intended to be called by Machine::openConfigLoader() only.
484 *
485 * @param aOldPath old path (full)
486 * @param aNewPath new path (full)
487 *
488 * @note Locks this object + children for writing.
489 */
490void Snapshot::updateSavedStatePaths (const char *aOldPath, const char *aNewPath)
491{
492 LogFlowThisFunc (("aOldPath={%s} aNewPath={%s}\n", aOldPath, aNewPath));
493
494 AssertReturnVoid (aOldPath);
495 AssertReturnVoid (aNewPath);
496
497 AutoWriteLock alock (this);
498 AssertReturnVoid (isReady());
499
500 Utf8Str path = mData.mMachine->mSSData->mStateFilePath;
501 LogFlowThisFunc (("Snap[%ls].statePath={%s}\n", mData.mName.raw(), path.raw()));
502
503 /* state file may be NULL (for offline snapshots) */
504 if (path && RTPathStartsWith (path, aOldPath))
505 {
506 path = Utf8StrFmt ("%s%s", aNewPath, path.raw() + strlen (aOldPath));
507 mData.mMachine->mSSData->mStateFilePath = path;
508
509 LogFlowThisFunc (("-> updated: {%s}\n", path.raw()));
510 }
511
512 AutoWriteLock chLock (childrenLock ());
513 for (SnapshotList::const_iterator it = children().begin();
514 it != children().end(); ++ it)
515 {
516 (*it)->updateSavedStatePaths (aOldPath, aNewPath);
517 }
518}
519
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette