VirtualBox

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

Last change on this file since 17649 was 17260, checked in by vboxsync, 16 years ago

#3551: “Main: Replace remaining collections with safe arrays”
Replace SnapshotCollection. Reviewed by dmik. Tested with GUI.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.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, IN_BSTR aName, IN_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_FAIL);
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) (OUT_GUID aId)
168{
169 CheckComArgOutPointerValid(aId);
170
171 AutoWriteLock alock (this);
172 CHECK_READY();
173
174 mData.mId.cloneTo (aId);
175 return S_OK;
176}
177
178STDMETHODIMP Snapshot::COMGETTER(Name) (BSTR *aName)
179{
180 CheckComArgOutPointerValid(aName);
181
182 AutoWriteLock alock (this);
183 CHECK_READY();
184
185 mData.mName.cloneTo (aName);
186 return S_OK;
187}
188
189/**
190 * @note Locks this object for writing, then calls Machine::onSnapshotChange()
191 * (see its lock requirements).
192 */
193STDMETHODIMP Snapshot::COMSETTER(Name) (IN_BSTR aName)
194{
195 CheckComArgNotNull(aName);
196
197 AutoWriteLock alock (this);
198 CHECK_READY();
199
200 if (mData.mName != aName)
201 {
202 mData.mName = aName;
203
204 alock.leave(); /* Important! (child->parent locks are forbidden) */
205
206 return mData.mMachine->onSnapshotChange (this);
207 }
208
209 return S_OK;
210}
211
212STDMETHODIMP Snapshot::COMGETTER(Description) (BSTR *aDescription)
213{
214 CheckComArgOutPointerValid(aDescription);
215
216 AutoWriteLock alock (this);
217 CHECK_READY();
218
219 mData.mDescription.cloneTo (aDescription);
220 return S_OK;
221}
222
223STDMETHODIMP Snapshot::COMSETTER(Description) (IN_BSTR aDescription)
224{
225 CheckComArgNotNull(aDescription);
226
227 AutoWriteLock alock (this);
228 CHECK_READY();
229
230 if (mData.mDescription != aDescription)
231 {
232 mData.mDescription = aDescription;
233
234 alock.leave(); /* Important! (child->parent locks are forbidden) */
235
236 return mData.mMachine->onSnapshotChange (this);
237 }
238
239 return S_OK;
240}
241
242STDMETHODIMP Snapshot::COMGETTER(TimeStamp) (LONG64 *aTimeStamp)
243{
244 CheckComArgOutPointerValid(aTimeStamp);
245
246 AutoWriteLock alock (this);
247 CHECK_READY();
248
249 *aTimeStamp = RTTimeSpecGetMilli (&mData.mTimeStamp);
250 return S_OK;
251}
252
253STDMETHODIMP Snapshot::COMGETTER(Online) (BOOL *aOnline)
254{
255 CheckComArgOutPointerValid(aOnline);
256
257 AutoWriteLock alock (this);
258 CHECK_READY();
259
260 *aOnline = !stateFilePath().isNull();
261 return S_OK;
262}
263
264STDMETHODIMP Snapshot::COMGETTER(Machine) (IMachine **aMachine)
265{
266 CheckComArgOutPointerValid(aMachine);
267
268 AutoWriteLock alock (this);
269 CHECK_READY();
270
271 mData.mMachine.queryInterfaceTo (aMachine);
272 return S_OK;
273}
274
275STDMETHODIMP Snapshot::COMGETTER(Parent) (ISnapshot **aParent)
276{
277 CheckComArgOutPointerValid(aParent);
278
279 AutoWriteLock alock (this);
280 CHECK_READY();
281
282 mParent.queryInterfaceTo (aParent);
283 return S_OK;
284}
285
286STDMETHODIMP Snapshot::COMGETTER(Children) (ComSafeArrayOut (ISnapshot *, aChildren))
287{
288 CheckComArgOutSafeArrayPointerValid(aChildren);
289
290 AutoWriteLock alock (this);
291 CHECK_READY();
292
293 AutoWriteLock chLock (childrenLock ());
294
295 SafeIfaceArray <ISnapshot> collection (children());
296 collection.detachTo (ComSafeArrayOutArg (aChildren));
297
298 return S_OK;
299}
300
301// public methods only for internal purposes
302////////////////////////////////////////////////////////////////////////////////
303
304/**
305 * @note
306 * Must be called from under the object's lock!
307 */
308const Bstr &Snapshot::stateFilePath() const
309{
310 return mData.mMachine->mSSData->mStateFilePath;
311}
312
313/**
314 * Returns the number of children of this snapshot, including grand-children,
315 * etc.
316 */
317ULONG Snapshot::descendantCount()
318{
319 AutoWriteLock alock(this);
320 AssertReturn (isReady(), 0);
321
322 AutoWriteLock chLock (childrenLock ());
323
324 ULONG count = children().size();
325
326 for (SnapshotList::const_iterator it = children().begin();
327 it != children().end(); ++ it)
328 {
329 count += (*it)->descendantCount();
330 }
331
332 return count;
333}
334
335/**
336 * Searches for a snapshot with the given ID among children, grand-children,
337 * etc. of this snapshot. This snapshot itself is also included in the search.
338 */
339ComObjPtr <Snapshot> Snapshot::findChildOrSelf (IN_GUID aId)
340{
341 ComObjPtr <Snapshot> child;
342
343 AutoWriteLock alock (this);
344 AssertReturn (isReady(), child);
345
346 if (mData.mId == aId)
347 child = this;
348 else
349 {
350 AutoWriteLock chLock (childrenLock ());
351 for (SnapshotList::const_iterator it = children().begin();
352 !child && it != children().end(); ++ it)
353 {
354 child = (*it)->findChildOrSelf (aId);
355 }
356 }
357
358 return child;
359}
360
361/**
362 * Searches for a first snapshot with the given name among children,
363 * grand-children, etc. of this snapshot. This snapshot itself is also included
364 * in the search.
365 */
366ComObjPtr <Snapshot> Snapshot::findChildOrSelf (IN_BSTR aName)
367{
368 ComObjPtr <Snapshot> child;
369 AssertReturn (aName, child);
370
371 AutoWriteLock alock (this);
372 AssertReturn (isReady(), child);
373
374 if (mData.mName == aName)
375 child = this;
376 else
377 {
378 AutoWriteLock chLock (childrenLock ());
379 for (SnapshotList::const_iterator it = children().begin();
380 !child && it != children().end(); ++ it)
381 {
382 child = (*it)->findChildOrSelf (aName);
383 }
384 }
385
386 return child;
387}
388
389/**
390 * Checks if the specified path change affects the saved state file path of
391 * this snapshot or any of its (grand-)children and updates it accordingly.
392 *
393 * Intended to be called by Machine::openConfigLoader() only.
394 *
395 * @param aOldPath old path (full)
396 * @param aNewPath new path (full)
397 *
398 * @note Locks this object + children for writing.
399 */
400void Snapshot::updateSavedStatePaths (const char *aOldPath, const char *aNewPath)
401{
402 LogFlowThisFunc (("aOldPath={%s} aNewPath={%s}\n", aOldPath, aNewPath));
403
404 AssertReturnVoid (aOldPath);
405 AssertReturnVoid (aNewPath);
406
407 AutoWriteLock alock (this);
408 AssertReturnVoid (isReady());
409
410 Utf8Str path = mData.mMachine->mSSData->mStateFilePath;
411 LogFlowThisFunc (("Snap[%ls].statePath={%s}\n", mData.mName.raw(), path.raw()));
412
413 /* state file may be NULL (for offline snapshots) */
414 if (path && RTPathStartsWith (path, aOldPath))
415 {
416 path = Utf8StrFmt ("%s%s", aNewPath, path.raw() + strlen (aOldPath));
417 mData.mMachine->mSSData->mStateFilePath = path;
418
419 LogFlowThisFunc (("-> updated: {%s}\n", path.raw()));
420 }
421
422 AutoWriteLock chLock (childrenLock ());
423 for (SnapshotList::const_iterator it = children().begin();
424 it != children().end(); ++ it)
425 {
426 (*it)->updateSavedStatePaths (aOldPath, aNewPath);
427 }
428}
429
430/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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