VirtualBox

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

Last change on this file since 14772 was 14772, checked in by vboxsync, 15 years ago

Added vim modelines to aid following coding guidelines, like no tabs,
similar to what is already in the xidl file.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 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_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) (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 * Checks if the specified path change affects the saved state file path of
403 * this snapshot or any of its (grand-)children and updates it accordingly.
404 *
405 * Intended to be called by Machine::openConfigLoader() only.
406 *
407 * @param aOldPath old path (full)
408 * @param aNewPath new path (full)
409 *
410 * @note Locks this object + children for writing.
411 */
412void Snapshot::updateSavedStatePaths (const char *aOldPath, const char *aNewPath)
413{
414 LogFlowThisFunc (("aOldPath={%s} aNewPath={%s}\n", aOldPath, aNewPath));
415
416 AssertReturnVoid (aOldPath);
417 AssertReturnVoid (aNewPath);
418
419 AutoWriteLock alock (this);
420 AssertReturnVoid (isReady());
421
422 Utf8Str path = mData.mMachine->mSSData->mStateFilePath;
423 LogFlowThisFunc (("Snap[%ls].statePath={%s}\n", mData.mName.raw(), path.raw()));
424
425 /* state file may be NULL (for offline snapshots) */
426 if (path && RTPathStartsWith (path, aOldPath))
427 {
428 path = Utf8StrFmt ("%s%s", aNewPath, path.raw() + strlen (aOldPath));
429 mData.mMachine->mSSData->mStateFilePath = path;
430
431 LogFlowThisFunc (("-> updated: {%s}\n", path.raw()));
432 }
433
434 AutoWriteLock chLock (childrenLock ());
435 for (SnapshotList::const_iterator it = children().begin();
436 it != children().end(); ++ it)
437 {
438 (*it)->updateSavedStatePaths (aOldPath, aNewPath);
439 }
440}
441
442/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use