VirtualBox

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

Last change on this file since 16596 was 15051, checked in by vboxsync, 16 years ago

Main: Cleaned up the long standing const BSTR = const (OLECHAR *) on WIn32 vs (const PRunichar) * on XPCOM clash. Cleaned up BSTR/GUID macros (IN_BSTR replaces INPTR BSTR, IN_GUID replaces INPTR GUIDPARAM, OUT_GUID replaces GUIDPARAMOUT).

  • 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) (ISnapshotCollection **aChildren)
287{
288 CheckComArgOutPointerValid(aChildren);
289
290 AutoWriteLock alock (this);
291 CHECK_READY();
292
293 AutoWriteLock chLock (childrenLock ());
294
295 ComObjPtr <SnapshotCollection> collection;
296 collection.createObject();
297 collection->init (children());
298 collection.queryInterfaceTo (aChildren);
299
300 return S_OK;
301}
302
303// public methods only for internal purposes
304////////////////////////////////////////////////////////////////////////////////
305
306/**
307 * @note
308 * Must be called from under the object's lock!
309 */
310const Bstr &Snapshot::stateFilePath() const
311{
312 return mData.mMachine->mSSData->mStateFilePath;
313}
314
315/**
316 * Returns the number of children of this snapshot, including grand-children,
317 * etc.
318 */
319ULONG Snapshot::descendantCount()
320{
321 AutoWriteLock alock(this);
322 AssertReturn (isReady(), 0);
323
324 AutoWriteLock chLock (childrenLock ());
325
326 ULONG count = children().size();
327
328 for (SnapshotList::const_iterator it = children().begin();
329 it != children().end(); ++ it)
330 {
331 count += (*it)->descendantCount();
332 }
333
334 return count;
335}
336
337/**
338 * Searches for a snapshot with the given ID among children, grand-children,
339 * etc. of this snapshot. This snapshot itself is also included in the search.
340 */
341ComObjPtr <Snapshot> Snapshot::findChildOrSelf (IN_GUID aId)
342{
343 ComObjPtr <Snapshot> child;
344
345 AutoWriteLock alock (this);
346 AssertReturn (isReady(), child);
347
348 if (mData.mId == aId)
349 child = this;
350 else
351 {
352 AutoWriteLock chLock (childrenLock ());
353 for (SnapshotList::const_iterator it = children().begin();
354 !child && it != children().end(); ++ it)
355 {
356 child = (*it)->findChildOrSelf (aId);
357 }
358 }
359
360 return child;
361}
362
363/**
364 * Searches for a first snapshot with the given name among children,
365 * grand-children, etc. of this snapshot. This snapshot itself is also included
366 * in the search.
367 */
368ComObjPtr <Snapshot> Snapshot::findChildOrSelf (IN_BSTR aName)
369{
370 ComObjPtr <Snapshot> child;
371 AssertReturn (aName, child);
372
373 AutoWriteLock alock (this);
374 AssertReturn (isReady(), child);
375
376 if (mData.mName == aName)
377 child = this;
378 else
379 {
380 AutoWriteLock chLock (childrenLock ());
381 for (SnapshotList::const_iterator it = children().begin();
382 !child && it != children().end(); ++ it)
383 {
384 child = (*it)->findChildOrSelf (aName);
385 }
386 }
387
388 return child;
389}
390
391/**
392 * Checks if the specified path change affects the saved state file path of
393 * this snapshot or any of its (grand-)children and updates it accordingly.
394 *
395 * Intended to be called by Machine::openConfigLoader() only.
396 *
397 * @param aOldPath old path (full)
398 * @param aNewPath new path (full)
399 *
400 * @note Locks this object + children for writing.
401 */
402void Snapshot::updateSavedStatePaths (const char *aOldPath, const char *aNewPath)
403{
404 LogFlowThisFunc (("aOldPath={%s} aNewPath={%s}\n", aOldPath, aNewPath));
405
406 AssertReturnVoid (aOldPath);
407 AssertReturnVoid (aNewPath);
408
409 AutoWriteLock alock (this);
410 AssertReturnVoid (isReady());
411
412 Utf8Str path = mData.mMachine->mSSData->mStateFilePath;
413 LogFlowThisFunc (("Snap[%ls].statePath={%s}\n", mData.mName.raw(), path.raw()));
414
415 /* state file may be NULL (for offline snapshots) */
416 if (path && RTPathStartsWith (path, aOldPath))
417 {
418 path = Utf8StrFmt ("%s%s", aNewPath, path.raw() + strlen (aOldPath));
419 mData.mMachine->mSSData->mStateFilePath = path;
420
421 LogFlowThisFunc (("-> updated: {%s}\n", path.raw()));
422 }
423
424 AutoWriteLock chLock (childrenLock ());
425 for (SnapshotList::const_iterator it = children().begin();
426 it != children().end(); ++ it)
427 {
428 (*it)->updateSavedStatePaths (aOldPath, aNewPath);
429 }
430}
431
432/* 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