[13580] | 1 | /* $Id: MediumImpl.cpp 16560 2009-02-06 18:06:04Z vboxsync $ */
|
---|
| 2 |
|
---|
| 3 | /** @file
|
---|
| 4 | *
|
---|
| 5 | * VirtualBox COM class implementation
|
---|
| 6 | */
|
---|
| 7 |
|
---|
| 8 | /*
|
---|
| 9 | * Copyright (C) 2008 Sun Microsystems, Inc.
|
---|
| 10 | *
|
---|
| 11 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
| 12 | * available from http://www.virtualbox.org. This file is free software;
|
---|
| 13 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
| 14 | * General Public License (GPL) as published by the Free Software
|
---|
| 15 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
| 16 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
| 17 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
| 18 | *
|
---|
| 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
---|
| 20 | * Clara, CA 95054 USA or visit http://www.sun.com if you need
|
---|
| 21 | * additional information or have any questions.
|
---|
| 22 | */
|
---|
| 23 |
|
---|
| 24 | #include "MediumImpl.h"
|
---|
| 25 |
|
---|
| 26 | #include "VirtualBoxImpl.h"
|
---|
| 27 |
|
---|
| 28 | #include "Logging.h"
|
---|
| 29 |
|
---|
| 30 | #include <VBox/com/array.h>
|
---|
| 31 |
|
---|
[16560] | 32 | #include <VBox/err.h>
|
---|
| 33 | #include <VBox/settings.h>
|
---|
| 34 |
|
---|
[13580] | 35 | #include <iprt/param.h>
|
---|
| 36 | #include <iprt/path.h>
|
---|
| 37 | #include <iprt/file.h>
|
---|
| 38 |
|
---|
| 39 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 40 | // MediumBase class
|
---|
| 41 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 42 |
|
---|
| 43 | // constructor / destructor
|
---|
| 44 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 45 |
|
---|
| 46 | DEFINE_EMPTY_CTOR_DTOR (MediumBase)
|
---|
| 47 |
|
---|
| 48 | // protected initializer/uninitializer for internal purposes only
|
---|
| 49 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 50 |
|
---|
| 51 | // IMedium properties
|
---|
| 52 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 53 |
|
---|
[15051] | 54 | STDMETHODIMP MediumBase::COMGETTER(Id) (OUT_GUID aId)
|
---|
[13580] | 55 | {
|
---|
[15202] | 56 | CheckComArgOutPointerValid (aId);
|
---|
[13580] | 57 |
|
---|
| 58 | AutoCaller autoCaller (this);
|
---|
| 59 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 60 |
|
---|
[14931] | 61 | AutoReadLock alock (this);
|
---|
| 62 |
|
---|
[13580] | 63 | m.id.cloneTo (aId);
|
---|
| 64 |
|
---|
| 65 | return S_OK;
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | STDMETHODIMP MediumBase::COMGETTER(Description) (BSTR *aDescription)
|
---|
| 69 | {
|
---|
[15202] | 70 | CheckComArgOutPointerValid (aDescription);
|
---|
[13580] | 71 |
|
---|
| 72 | AutoCaller autoCaller (this);
|
---|
| 73 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 74 |
|
---|
| 75 | AutoReadLock alock (this);
|
---|
| 76 |
|
---|
| 77 | m.description.cloneTo (aDescription);
|
---|
| 78 |
|
---|
| 79 | return S_OK;
|
---|
| 80 | }
|
---|
| 81 |
|
---|
[15051] | 82 | STDMETHODIMP MediumBase::COMSETTER(Description) (IN_BSTR aDescription)
|
---|
[13580] | 83 | {
|
---|
[15202] | 84 | CheckComArgNotNull (aDescription);
|
---|
[13580] | 85 |
|
---|
| 86 | AutoCaller autoCaller (this);
|
---|
| 87 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 88 |
|
---|
| 89 | AutoWriteLock alock (this);
|
---|
| 90 |
|
---|
| 91 | /// @todo update m.description and save the global registry (and local
|
---|
| 92 | /// registries of portable VMs referring to this medium), this will also
|
---|
| 93 | /// require to add the mRegistered flag to data
|
---|
| 94 |
|
---|
[14715] | 95 | ReturnComNotImplemented();
|
---|
[13580] | 96 | }
|
---|
| 97 |
|
---|
| 98 | STDMETHODIMP MediumBase::COMGETTER(State) (MediaState_T *aState)
|
---|
| 99 | {
|
---|
[14972] | 100 | CheckComArgOutPointerValid(aState);
|
---|
[13580] | 101 |
|
---|
| 102 | AutoCaller autoCaller (this);
|
---|
| 103 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 104 |
|
---|
| 105 | /* queryInfo() locks this for writing. */
|
---|
| 106 | AutoWriteLock alock (this);
|
---|
| 107 |
|
---|
| 108 | HRESULT rc = S_OK;
|
---|
| 109 |
|
---|
| 110 | switch (m.state)
|
---|
| 111 | {
|
---|
| 112 | case MediaState_Created:
|
---|
| 113 | case MediaState_Inaccessible:
|
---|
| 114 | case MediaState_LockedRead:
|
---|
| 115 | case MediaState_LockedWrite:
|
---|
| 116 | {
|
---|
| 117 | rc = queryInfo();
|
---|
| 118 | break;
|
---|
| 119 | }
|
---|
| 120 | default:
|
---|
| 121 | break;
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 | *aState = m.state;
|
---|
| 125 |
|
---|
| 126 | return rc;
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | STDMETHODIMP MediumBase::COMGETTER(Location) (BSTR *aLocation)
|
---|
| 130 | {
|
---|
[14972] | 131 | CheckComArgOutPointerValid(aLocation);
|
---|
[13580] | 132 |
|
---|
| 133 | AutoCaller autoCaller (this);
|
---|
| 134 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 135 |
|
---|
| 136 | AutoReadLock alock (this);
|
---|
| 137 |
|
---|
| 138 | m.locationFull.cloneTo (aLocation);
|
---|
| 139 |
|
---|
| 140 | return S_OK;
|
---|
| 141 | }
|
---|
| 142 |
|
---|
[15051] | 143 | STDMETHODIMP MediumBase::COMSETTER(Location) (IN_BSTR aLocation)
|
---|
[13580] | 144 | {
|
---|
[15202] | 145 | CheckComArgNotNull (aLocation);
|
---|
[13580] | 146 |
|
---|
| 147 | AutoCaller autoCaller (this);
|
---|
| 148 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 149 |
|
---|
| 150 | AutoWriteLock alock (this);
|
---|
| 151 |
|
---|
| 152 | /// @todo NEWMEDIA for file names, add the default extension if no extension
|
---|
| 153 | /// is present (using the information from the VD backend which also implies
|
---|
| 154 | /// that one more parameter should be passed to setLocation() requesting
|
---|
| 155 | /// that functionality since it is only allwed when called from this method
|
---|
| 156 |
|
---|
| 157 | /// @todo NEWMEDIA rename the file and set m.location on success, then save
|
---|
| 158 | /// the global registry (and local registries of portable VMs referring to
|
---|
| 159 | /// this medium), this will also require to add the mRegistered flag to data
|
---|
| 160 |
|
---|
[14715] | 161 | ReturnComNotImplemented();
|
---|
[13580] | 162 | }
|
---|
| 163 |
|
---|
| 164 | STDMETHODIMP MediumBase::COMGETTER(Name) (BSTR *aName)
|
---|
| 165 | {
|
---|
[15202] | 166 | CheckComArgOutPointerValid (aName);
|
---|
[13580] | 167 |
|
---|
| 168 | AutoCaller autoCaller (this);
|
---|
| 169 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 170 |
|
---|
| 171 | AutoReadLock alock (this);
|
---|
| 172 |
|
---|
| 173 | name().cloneTo (aName);
|
---|
| 174 |
|
---|
| 175 | return S_OK;
|
---|
| 176 | }
|
---|
| 177 |
|
---|
| 178 | STDMETHODIMP MediumBase::COMGETTER(Size) (ULONG64 *aSize)
|
---|
| 179 | {
|
---|
[15202] | 180 | CheckComArgOutPointerValid (aSize);
|
---|
[13580] | 181 |
|
---|
| 182 | AutoCaller autoCaller (this);
|
---|
| 183 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 184 |
|
---|
| 185 | AutoReadLock alock (this);
|
---|
| 186 |
|
---|
| 187 | *aSize = m.size;
|
---|
| 188 |
|
---|
| 189 | return S_OK;
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 | STDMETHODIMP MediumBase::COMGETTER(LastAccessError) (BSTR *aLastAccessError)
|
---|
| 193 | {
|
---|
[15202] | 194 | CheckComArgOutPointerValid (aLastAccessError);
|
---|
[13580] | 195 |
|
---|
| 196 | AutoCaller autoCaller (this);
|
---|
| 197 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 198 |
|
---|
| 199 | AutoReadLock alock (this);
|
---|
| 200 |
|
---|
| 201 | m.lastAccessError.cloneTo (aLastAccessError);
|
---|
| 202 |
|
---|
| 203 | return S_OK;
|
---|
| 204 | }
|
---|
| 205 |
|
---|
| 206 | STDMETHODIMP MediumBase::COMGETTER(MachineIds) (ComSafeGUIDArrayOut (aMachineIds))
|
---|
| 207 | {
|
---|
| 208 | if (ComSafeGUIDArrayOutIsNull (aMachineIds))
|
---|
| 209 | return E_POINTER;
|
---|
| 210 |
|
---|
| 211 | AutoCaller autoCaller (this);
|
---|
| 212 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 213 |
|
---|
| 214 | AutoReadLock alock (this);
|
---|
| 215 |
|
---|
| 216 | com::SafeGUIDArray machineIds;
|
---|
| 217 |
|
---|
| 218 | if (m.backRefs.size() != 0)
|
---|
| 219 | {
|
---|
| 220 | machineIds.reset (m.backRefs.size());
|
---|
| 221 |
|
---|
| 222 | size_t i = 0;
|
---|
| 223 | for (BackRefList::const_iterator it = m.backRefs.begin();
|
---|
| 224 | it != m.backRefs.end(); ++ it, ++ i)
|
---|
| 225 | {
|
---|
| 226 | machineIds [i] = it->machineId;
|
---|
| 227 | }
|
---|
| 228 | }
|
---|
| 229 |
|
---|
| 230 | machineIds.detachTo (ComSafeGUIDArrayOutArg (aMachineIds));
|
---|
| 231 |
|
---|
| 232 | return S_OK;
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | // IMedium methods
|
---|
| 236 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 237 |
|
---|
[15051] | 238 | STDMETHODIMP MediumBase::GetSnapshotIds (IN_GUID aMachineId,
|
---|
[13580] | 239 | ComSafeGUIDArrayOut (aSnapshotIds))
|
---|
| 240 | {
|
---|
[15202] | 241 | CheckComArgExpr (aMachineId, Guid (aMachineId).isEmpty() == false);
|
---|
| 242 | CheckComArgOutSafeArrayPointerValid (aSnapshotIds);
|
---|
[13580] | 243 |
|
---|
| 244 | AutoCaller autoCaller (this);
|
---|
| 245 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 246 |
|
---|
| 247 | AutoReadLock alock (this);
|
---|
| 248 |
|
---|
| 249 | com::SafeGUIDArray snapshotIds;
|
---|
| 250 |
|
---|
| 251 | for (BackRefList::const_iterator it = m.backRefs.begin();
|
---|
| 252 | it != m.backRefs.end(); ++ it)
|
---|
| 253 | {
|
---|
| 254 | if (it->machineId == aMachineId)
|
---|
| 255 | {
|
---|
| 256 | size_t size = it->snapshotIds.size();
|
---|
| 257 |
|
---|
| 258 | /* if the medium is attached to the machine in the current state, we
|
---|
| 259 | * return its ID as the first element of the array */
|
---|
| 260 | if (it->inCurState)
|
---|
| 261 | ++ size;
|
---|
| 262 |
|
---|
| 263 | if (size > 0)
|
---|
| 264 | {
|
---|
| 265 | snapshotIds.reset (size);
|
---|
| 266 |
|
---|
| 267 | size_t j = 0;
|
---|
| 268 | if (it->inCurState)
|
---|
| 269 | snapshotIds [j ++] = it->machineId;
|
---|
| 270 |
|
---|
| 271 | for (BackRef::GuidList::const_iterator jt =
|
---|
| 272 | it->snapshotIds.begin();
|
---|
| 273 | jt != it->snapshotIds.end(); ++ jt, ++ j)
|
---|
| 274 | {
|
---|
| 275 | snapshotIds [j] = *jt;
|
---|
| 276 | }
|
---|
| 277 | }
|
---|
| 278 |
|
---|
| 279 | break;
|
---|
| 280 | }
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 | snapshotIds.detachTo (ComSafeGUIDArrayOutArg (aSnapshotIds));
|
---|
| 284 |
|
---|
| 285 | return S_OK;
|
---|
| 286 | }
|
---|
| 287 |
|
---|
| 288 | /**
|
---|
| 289 | * @note @a aState may be NULL if the state value is not needed (only for
|
---|
| 290 | * in-process calls).
|
---|
| 291 | */
|
---|
| 292 | STDMETHODIMP MediumBase::LockRead (MediaState_T *aState)
|
---|
| 293 | {
|
---|
| 294 | AutoCaller autoCaller (this);
|
---|
| 295 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 296 |
|
---|
| 297 | AutoWriteLock alock (this);
|
---|
| 298 |
|
---|
| 299 | /* return the current state before */
|
---|
| 300 | if (aState)
|
---|
| 301 | *aState = m.state;
|
---|
| 302 |
|
---|
| 303 | HRESULT rc = S_OK;
|
---|
| 304 |
|
---|
| 305 | switch (m.state)
|
---|
| 306 | {
|
---|
| 307 | case MediaState_Created:
|
---|
| 308 | case MediaState_Inaccessible:
|
---|
| 309 | case MediaState_LockedRead:
|
---|
| 310 | {
|
---|
| 311 | ++ m.readers;
|
---|
| 312 |
|
---|
| 313 | ComAssertMsgBreak (m.readers != 0, ("Counter overflow"),
|
---|
| 314 | rc = E_FAIL);
|
---|
| 315 |
|
---|
| 316 | if (m.state == MediaState_Created)
|
---|
| 317 | m.accessibleInLock = true;
|
---|
| 318 | else if (m.state == MediaState_Inaccessible)
|
---|
| 319 | m.accessibleInLock = false;
|
---|
| 320 |
|
---|
| 321 | m.state = MediaState_LockedRead;
|
---|
| 322 |
|
---|
| 323 | break;
|
---|
| 324 | }
|
---|
| 325 | default:
|
---|
| 326 | {
|
---|
| 327 | rc = setStateError();
|
---|
| 328 | break;
|
---|
| 329 | }
|
---|
| 330 | }
|
---|
| 331 |
|
---|
| 332 | return rc;
|
---|
| 333 | }
|
---|
| 334 |
|
---|
| 335 | /**
|
---|
| 336 | * @note @a aState may be NULL if the state value is not needed (only for
|
---|
| 337 | * in-process calls).
|
---|
| 338 | */
|
---|
| 339 | STDMETHODIMP MediumBase::UnlockRead (MediaState_T *aState)
|
---|
| 340 | {
|
---|
| 341 | AutoCaller autoCaller (this);
|
---|
| 342 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 343 |
|
---|
| 344 | AutoWriteLock alock (this);
|
---|
| 345 |
|
---|
| 346 | HRESULT rc = S_OK;
|
---|
| 347 |
|
---|
| 348 | switch (m.state)
|
---|
| 349 | {
|
---|
| 350 | case MediaState_LockedRead:
|
---|
| 351 | {
|
---|
| 352 | if (m.queryInfoSem == NIL_RTSEMEVENTMULTI)
|
---|
| 353 | {
|
---|
| 354 | Assert (m.readers != 0);
|
---|
| 355 | -- m.readers;
|
---|
| 356 |
|
---|
| 357 | /* Reset the state after the last reader */
|
---|
| 358 | if (m.readers == 0)
|
---|
| 359 | {
|
---|
| 360 | if (m.accessibleInLock)
|
---|
| 361 | m.state = MediaState_Created;
|
---|
| 362 | else
|
---|
| 363 | m.state = MediaState_Inaccessible;
|
---|
| 364 | }
|
---|
| 365 |
|
---|
| 366 | break;
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 | /* otherwise, queryInfo() is in progress; fall through */
|
---|
| 370 | }
|
---|
| 371 | default:
|
---|
| 372 | {
|
---|
[15178] | 373 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 374 | tr ("Medium '%ls' is not locked for reading"),
|
---|
| 375 | m.locationFull.raw());
|
---|
| 376 | break;
|
---|
| 377 | }
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | /* return the current state after */
|
---|
| 381 | if (aState)
|
---|
| 382 | *aState = m.state;
|
---|
| 383 |
|
---|
| 384 | return rc;
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | /**
|
---|
| 388 | * @note @a aState may be NULL if the state value is not needed (only for
|
---|
| 389 | * in-process calls).
|
---|
| 390 | */
|
---|
| 391 | STDMETHODIMP MediumBase::LockWrite (MediaState_T *aState)
|
---|
| 392 | {
|
---|
| 393 | AutoCaller autoCaller (this);
|
---|
| 394 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 395 |
|
---|
| 396 | AutoWriteLock alock (this);
|
---|
| 397 |
|
---|
| 398 | /* return the current state before */
|
---|
| 399 | if (aState)
|
---|
| 400 | *aState = m.state;
|
---|
| 401 |
|
---|
| 402 | HRESULT rc = S_OK;
|
---|
| 403 |
|
---|
| 404 | switch (m.state)
|
---|
| 405 | {
|
---|
| 406 | case MediaState_Created:
|
---|
| 407 | case MediaState_Inaccessible:
|
---|
| 408 | {
|
---|
| 409 | if (m.state == MediaState_Created)
|
---|
| 410 | m.accessibleInLock = true;
|
---|
| 411 | else if (m.state == MediaState_Inaccessible)
|
---|
| 412 | m.accessibleInLock = false;
|
---|
| 413 |
|
---|
| 414 | m.state = MediaState_LockedWrite;
|
---|
| 415 | break;
|
---|
| 416 | }
|
---|
| 417 | default:
|
---|
| 418 | {
|
---|
| 419 | rc = setStateError();
|
---|
| 420 | break;
|
---|
| 421 | }
|
---|
| 422 | }
|
---|
| 423 |
|
---|
| 424 | return rc;
|
---|
| 425 | }
|
---|
| 426 |
|
---|
| 427 | /**
|
---|
| 428 | * @note @a aState may be NULL if the state value is not needed (only for
|
---|
| 429 | * in-process calls).
|
---|
| 430 | */
|
---|
| 431 | STDMETHODIMP MediumBase::UnlockWrite (MediaState_T *aState)
|
---|
| 432 | {
|
---|
| 433 | AutoCaller autoCaller (this);
|
---|
| 434 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 435 |
|
---|
| 436 | AutoWriteLock alock (this);
|
---|
| 437 |
|
---|
| 438 | HRESULT rc = S_OK;
|
---|
| 439 |
|
---|
| 440 | switch (m.state)
|
---|
| 441 | {
|
---|
| 442 | case MediaState_LockedWrite:
|
---|
| 443 | {
|
---|
| 444 | if (m.accessibleInLock)
|
---|
| 445 | m.state = MediaState_Created;
|
---|
| 446 | else
|
---|
| 447 | m.state = MediaState_Inaccessible;
|
---|
| 448 | break;
|
---|
| 449 | }
|
---|
| 450 | default:
|
---|
| 451 | {
|
---|
[15178] | 452 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 453 | tr ("Medium '%ls' is not locked for writing"),
|
---|
| 454 | m.locationFull.raw());
|
---|
| 455 | break;
|
---|
| 456 | }
|
---|
| 457 | }
|
---|
| 458 |
|
---|
| 459 | /* return the current state after */
|
---|
| 460 | if (aState)
|
---|
| 461 | *aState = m.state;
|
---|
| 462 |
|
---|
| 463 | return rc;
|
---|
| 464 | }
|
---|
| 465 |
|
---|
| 466 | STDMETHODIMP MediumBase::Close()
|
---|
| 467 | {
|
---|
| 468 | AutoMayUninitSpan mayUninitSpan (this);
|
---|
| 469 | CheckComRCReturnRC (mayUninitSpan.rc());
|
---|
| 470 |
|
---|
| 471 | if (mayUninitSpan.alreadyInProgress())
|
---|
| 472 | return S_OK;
|
---|
| 473 |
|
---|
| 474 | /* unregisterWithVirtualBox() is assumed to always need a write mVirtualBox
|
---|
| 475 | * lock as it is intenede to modify its internal structires. Also, we want
|
---|
| 476 | * to unregister ourselves atomically after detecting that closure is
|
---|
| 477 | * possible to make sure that we don't do that after another thread has done
|
---|
| 478 | * VirtualBox::find*() but before it starts using us (provided that it holds
|
---|
| 479 | * a mVirtualBox lock of course). */
|
---|
| 480 |
|
---|
| 481 | AutoWriteLock vboxLock (mVirtualBox);
|
---|
| 482 |
|
---|
| 483 | bool wasCreated = true;
|
---|
| 484 |
|
---|
| 485 | switch (m.state)
|
---|
| 486 | {
|
---|
| 487 | case MediaState_NotCreated:
|
---|
| 488 | wasCreated = false;
|
---|
| 489 | break;
|
---|
| 490 | case MediaState_Created:
|
---|
| 491 | case MediaState_Inaccessible:
|
---|
| 492 | break;
|
---|
| 493 | default:
|
---|
| 494 | return setStateError();
|
---|
| 495 | }
|
---|
| 496 |
|
---|
| 497 | if (m.backRefs.size() != 0)
|
---|
[15178] | 498 | return setError (VBOX_E_OBJECT_IN_USE,
|
---|
[13580] | 499 | tr ("Medium '%ls' is attached to %d virtual machines"),
|
---|
| 500 | m.locationFull.raw(), m.backRefs.size());
|
---|
| 501 |
|
---|
| 502 | /* perform extra media-dependent close checks */
|
---|
| 503 | HRESULT rc = canClose();
|
---|
| 504 | CheckComRCReturnRC (rc);
|
---|
| 505 |
|
---|
| 506 | if (wasCreated)
|
---|
| 507 | {
|
---|
| 508 | /* remove from the list of known media before performing actual
|
---|
| 509 | * uninitialization (to keep the media registry consistent on
|
---|
| 510 | * failure to do so) */
|
---|
| 511 | rc = unregisterWithVirtualBox();
|
---|
| 512 | CheckComRCReturnRC (rc);
|
---|
| 513 | }
|
---|
| 514 |
|
---|
| 515 | /* cause uninit() to happen on success */
|
---|
| 516 | mayUninitSpan.acceptUninit();
|
---|
| 517 |
|
---|
| 518 | return S_OK;
|
---|
| 519 | }
|
---|
| 520 |
|
---|
| 521 | // public methods for internal purposes only
|
---|
| 522 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 523 |
|
---|
| 524 | /**
|
---|
| 525 | * Checks if the given change of \a aOldPath to \a aNewPath affects the location
|
---|
| 526 | * of this media and updates it if necessary to reflect the new location.
|
---|
| 527 | *
|
---|
| 528 | * @param aOldPath Old path (full).
|
---|
| 529 | * @param aNewPath New path (full).
|
---|
| 530 | *
|
---|
| 531 | * @note Locks this object for writing.
|
---|
| 532 | */
|
---|
| 533 | HRESULT MediumBase::updatePath (const char *aOldPath, const char *aNewPath)
|
---|
| 534 | {
|
---|
| 535 | AssertReturn (aOldPath, E_FAIL);
|
---|
| 536 | AssertReturn (aNewPath, E_FAIL);
|
---|
| 537 |
|
---|
| 538 | AutoCaller autoCaller (this);
|
---|
| 539 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 540 |
|
---|
| 541 | AutoWriteLock alock (this);
|
---|
| 542 |
|
---|
| 543 | LogFlowThisFunc (("locationFull.before='%s'\n", m.locationFull.raw()));
|
---|
| 544 |
|
---|
| 545 | Utf8Str path = m.locationFull;
|
---|
| 546 |
|
---|
| 547 | if (RTPathStartsWith (path, aOldPath))
|
---|
| 548 | {
|
---|
| 549 | Utf8Str newPath = Utf8StrFmt ("%s%s", aNewPath,
|
---|
| 550 | path.raw() + strlen (aOldPath));
|
---|
| 551 | path = newPath;
|
---|
| 552 |
|
---|
| 553 | mVirtualBox->calculateRelativePath (path, path);
|
---|
| 554 |
|
---|
| 555 | unconst (m.locationFull) = newPath;
|
---|
| 556 | unconst (m.location) = path;
|
---|
| 557 |
|
---|
| 558 | LogFlowThisFunc (("locationFull.after='%s'\n", m.locationFull.raw()));
|
---|
| 559 | }
|
---|
| 560 |
|
---|
| 561 | return S_OK;
|
---|
| 562 | }
|
---|
| 563 |
|
---|
| 564 | /**
|
---|
| 565 | * Adds the given machine and optionally the snapshot to the list of the objects
|
---|
| 566 | * this image is attached to.
|
---|
| 567 | *
|
---|
| 568 | * @param aMachineId Machine ID.
|
---|
| 569 | * @param aSnapshotId Snapshot ID; when non-empty, adds a snapshot attachment.
|
---|
| 570 | */
|
---|
| 571 | HRESULT MediumBase::attachTo (const Guid &aMachineId,
|
---|
| 572 | const Guid &aSnapshotId /*= Guid::Empty*/)
|
---|
| 573 | {
|
---|
| 574 | AssertReturn (!aMachineId.isEmpty(), E_FAIL);
|
---|
| 575 |
|
---|
| 576 | AutoCaller autoCaller (this);
|
---|
| 577 | AssertComRCReturnRC (autoCaller.rc());
|
---|
| 578 |
|
---|
| 579 | AutoWriteLock alock (this);
|
---|
| 580 |
|
---|
| 581 | switch (m.state)
|
---|
| 582 | {
|
---|
| 583 | case MediaState_Created:
|
---|
| 584 | case MediaState_Inaccessible:
|
---|
| 585 | case MediaState_LockedRead:
|
---|
| 586 | case MediaState_LockedWrite:
|
---|
| 587 | break;
|
---|
| 588 |
|
---|
| 589 | default:
|
---|
| 590 | return setStateError();
|
---|
| 591 | }
|
---|
| 592 |
|
---|
| 593 | HRESULT rc = canAttach (aMachineId, aSnapshotId);
|
---|
| 594 | CheckComRCReturnRC (rc);
|
---|
| 595 |
|
---|
| 596 | BackRefList::iterator it =
|
---|
| 597 | std::find_if (m.backRefs.begin(), m.backRefs.end(),
|
---|
| 598 | BackRef::EqualsTo (aMachineId));
|
---|
| 599 | if (it == m.backRefs.end())
|
---|
| 600 | {
|
---|
| 601 | BackRef ref (aMachineId, aSnapshotId);
|
---|
| 602 | m.backRefs.push_back (ref);
|
---|
| 603 |
|
---|
| 604 | return S_OK;
|
---|
| 605 | }
|
---|
| 606 |
|
---|
| 607 | if (aSnapshotId.isEmpty())
|
---|
| 608 | {
|
---|
| 609 | /* sanity: no duplicate attachments */
|
---|
| 610 | AssertReturn (!it->inCurState, E_FAIL);
|
---|
| 611 | it->inCurState = true;
|
---|
| 612 |
|
---|
| 613 | return S_OK;
|
---|
| 614 | }
|
---|
| 615 |
|
---|
| 616 | /* sanity: no duplicate attachments */
|
---|
| 617 | BackRef::GuidList::const_iterator jt =
|
---|
| 618 | std::find (it->snapshotIds.begin(), it->snapshotIds.end(), aSnapshotId);
|
---|
| 619 | AssertReturn (jt == it->snapshotIds.end(), E_FAIL);
|
---|
| 620 |
|
---|
| 621 | it->snapshotIds.push_back (aSnapshotId);
|
---|
| 622 |
|
---|
| 623 | return S_OK;
|
---|
| 624 | }
|
---|
| 625 |
|
---|
| 626 | /**
|
---|
| 627 | * Removes the given machine and optionally the snapshot from the list of the
|
---|
| 628 | * objects this image is attached to.
|
---|
| 629 | *
|
---|
| 630 | * @param aMachineId Machine ID.
|
---|
| 631 | * @param aSnapshotId Snapshot ID; when non-empty, removes the snapshot
|
---|
| 632 | * attachment.
|
---|
| 633 | */
|
---|
| 634 | HRESULT MediumBase::detachFrom (const Guid &aMachineId,
|
---|
| 635 | const Guid &aSnapshotId /*= Guid::Empty*/)
|
---|
| 636 | {
|
---|
| 637 | AssertReturn (!aMachineId.isEmpty(), E_FAIL);
|
---|
| 638 |
|
---|
| 639 | AutoCaller autoCaller (this);
|
---|
| 640 | AssertComRCReturnRC (autoCaller.rc());
|
---|
| 641 |
|
---|
| 642 | AutoWriteLock alock (this);
|
---|
| 643 |
|
---|
| 644 | BackRefList::iterator it =
|
---|
| 645 | std::find_if (m.backRefs.begin(), m.backRefs.end(),
|
---|
| 646 | BackRef::EqualsTo (aMachineId));
|
---|
| 647 | AssertReturn (it != m.backRefs.end(), E_FAIL);
|
---|
| 648 |
|
---|
| 649 | if (aSnapshotId.isEmpty())
|
---|
| 650 | {
|
---|
| 651 | /* remove the current state attachment */
|
---|
| 652 | it->inCurState = false;
|
---|
| 653 | }
|
---|
| 654 | else
|
---|
| 655 | {
|
---|
| 656 | /* remove the snapshot attachment */
|
---|
| 657 | BackRef::GuidList::iterator jt =
|
---|
| 658 | std::find (it->snapshotIds.begin(), it->snapshotIds.end(), aSnapshotId);
|
---|
| 659 |
|
---|
| 660 | AssertReturn (jt != it->snapshotIds.end(), E_FAIL);
|
---|
| 661 | it->snapshotIds.erase (jt);
|
---|
| 662 | }
|
---|
| 663 |
|
---|
| 664 | /* if the backref becomes empty, remove it */
|
---|
| 665 | if (it->inCurState == false && it->snapshotIds.size() == 0)
|
---|
| 666 | m.backRefs.erase (it);
|
---|
| 667 |
|
---|
| 668 | return S_OK;
|
---|
| 669 | }
|
---|
| 670 |
|
---|
| 671 | // protected methods
|
---|
| 672 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 673 |
|
---|
| 674 | /**
|
---|
| 675 | * Returns a short version of the location attribute.
|
---|
| 676 | *
|
---|
| 677 | * @note Must be called from under this object's read or write lock.
|
---|
| 678 | */
|
---|
| 679 | Utf8Str MediumBase::name()
|
---|
| 680 | {
|
---|
| 681 | Utf8Str location (m.locationFull);
|
---|
| 682 |
|
---|
| 683 | Utf8Str name = RTPathFilename (location);
|
---|
| 684 | return name;
|
---|
| 685 | }
|
---|
| 686 |
|
---|
| 687 | /**
|
---|
| 688 | * Sets the value of m.location and calculates the value of m.locationFull.
|
---|
| 689 | *
|
---|
| 690 | * @param aLocation Path to the image file (can be relative to the
|
---|
| 691 | * VirtualBox home directory).
|
---|
| 692 | *
|
---|
| 693 | * @note Must be called from under this object's write lock.
|
---|
| 694 | */
|
---|
[15051] | 695 | HRESULT MediumBase::setLocation (CBSTR aLocation)
|
---|
[13580] | 696 | {
|
---|
| 697 | /* get the full file name */
|
---|
| 698 | Utf8Str locationFull;
|
---|
| 699 | int vrc = mVirtualBox->calculateFullPath (Utf8Str (aLocation), locationFull);
|
---|
[13835] | 700 | if (RT_FAILURE (vrc))
|
---|
[13580] | 701 | return setError (E_FAIL,
|
---|
[13837] | 702 | tr ("Invalid image file location '%ls' (%Rrc)"),
|
---|
[13580] | 703 | aLocation, vrc);
|
---|
| 704 |
|
---|
| 705 | m.location = aLocation;
|
---|
| 706 | m.locationFull = locationFull;
|
---|
| 707 |
|
---|
| 708 | return S_OK;
|
---|
| 709 | }
|
---|
| 710 |
|
---|
| 711 | /**
|
---|
| 712 | * Queries information from the image file.
|
---|
| 713 | *
|
---|
| 714 | * As a result of this call, the accessibility state and data members such as
|
---|
| 715 | * size and description will be updated with the current information.
|
---|
| 716 | *
|
---|
| 717 | * @note This method may block during a system I/O call that checks image file
|
---|
| 718 | * accessibility.
|
---|
| 719 | *
|
---|
| 720 | * @note Locks this object for writing.
|
---|
| 721 | */
|
---|
| 722 | HRESULT MediumBase::queryInfo()
|
---|
| 723 | {
|
---|
| 724 | AutoWriteLock alock (this);
|
---|
| 725 |
|
---|
| 726 | AssertReturn (m.state == MediaState_Created ||
|
---|
| 727 | m.state == MediaState_Inaccessible ||
|
---|
| 728 | m.state == MediaState_LockedRead ||
|
---|
| 729 | m.state == MediaState_LockedWrite,
|
---|
| 730 | E_FAIL);
|
---|
| 731 |
|
---|
| 732 | int vrc = VINF_SUCCESS;
|
---|
| 733 |
|
---|
| 734 | /* check if a blocking queryInfo() call is in progress on some other thread,
|
---|
| 735 | * and wait for it to finish if so instead of querying data ourselves */
|
---|
| 736 | if (m.queryInfoSem != NIL_RTSEMEVENTMULTI)
|
---|
| 737 | {
|
---|
| 738 | Assert (m.state == MediaState_LockedRead);
|
---|
| 739 |
|
---|
| 740 | ++ m.queryInfoCallers;
|
---|
| 741 | alock.leave();
|
---|
| 742 |
|
---|
| 743 | vrc = RTSemEventMultiWait (m.queryInfoSem, RT_INDEFINITE_WAIT);
|
---|
| 744 |
|
---|
| 745 | alock.enter();
|
---|
| 746 | -- m.queryInfoCallers;
|
---|
| 747 |
|
---|
| 748 | if (m.queryInfoCallers == 0)
|
---|
| 749 | {
|
---|
| 750 | /* last waiting caller deletes the semaphore */
|
---|
| 751 | RTSemEventMultiDestroy (m.queryInfoSem);
|
---|
| 752 | m.queryInfoSem = NIL_RTSEMEVENTMULTI;
|
---|
| 753 | }
|
---|
| 754 |
|
---|
| 755 | AssertRC (vrc);
|
---|
| 756 |
|
---|
| 757 | return S_OK;
|
---|
| 758 | }
|
---|
| 759 |
|
---|
| 760 | /* lazily create a semaphore for possible callers */
|
---|
| 761 | vrc = RTSemEventMultiCreate (&m.queryInfoSem);
|
---|
| 762 | ComAssertRCRet (vrc, E_FAIL);
|
---|
| 763 |
|
---|
| 764 | bool tempStateSet = false;
|
---|
| 765 | if (m.state != MediaState_LockedRead &&
|
---|
| 766 | m.state != MediaState_LockedWrite)
|
---|
| 767 | {
|
---|
| 768 | /* Cause other methods to prevent any modifications before leaving the
|
---|
| 769 | * lock. Note that clients will never see this temporary state change
|
---|
| 770 | * directly since any COMGETTER(State) is (or will be) blocked until we
|
---|
| 771 | * finish and restore the actual state. This may be seen only through
|
---|
| 772 | * error messages reported by other methods. */
|
---|
| 773 | m.state = MediaState_LockedRead;
|
---|
| 774 | tempStateSet = true;
|
---|
| 775 | }
|
---|
| 776 |
|
---|
| 777 | /* leave the lock before a blocking operation */
|
---|
| 778 | alock.leave();
|
---|
| 779 |
|
---|
| 780 | bool success = false;
|
---|
| 781 |
|
---|
| 782 | /* get image file info */
|
---|
| 783 | {
|
---|
| 784 | RTFILE file;
|
---|
| 785 | vrc = RTFileOpen (&file, Utf8Str (m.locationFull), RTFILE_O_READ);
|
---|
| 786 | if (RT_SUCCESS (vrc))
|
---|
| 787 | {
|
---|
| 788 | vrc = RTFileGetSize (file, &m.size);
|
---|
| 789 |
|
---|
| 790 | RTFileClose (file);
|
---|
| 791 | }
|
---|
| 792 |
|
---|
| 793 | if (RT_FAILURE (vrc))
|
---|
| 794 | {
|
---|
| 795 | m.lastAccessError = Utf8StrFmt (
|
---|
[13837] | 796 | tr ("Could not access the image file '%ls' (%Rrc)"),
|
---|
[13580] | 797 | m.locationFull.raw(), vrc);
|
---|
| 798 | }
|
---|
| 799 |
|
---|
| 800 | success = (RT_SUCCESS (vrc));
|
---|
| 801 | }
|
---|
| 802 |
|
---|
| 803 | alock.enter();
|
---|
| 804 |
|
---|
| 805 | if (success)
|
---|
| 806 | m.lastAccessError.setNull();
|
---|
[15215] | 807 | else
|
---|
| 808 | LogWarningFunc (("'%ls' is not accessible (error='%ls', vrc=%Rrc)\n",
|
---|
| 809 | m.locationFull.raw(), m.lastAccessError.raw(), vrc));
|
---|
[13580] | 810 |
|
---|
| 811 | /* inform other callers if there are any */
|
---|
| 812 | if (m.queryInfoCallers > 0)
|
---|
| 813 | {
|
---|
| 814 | RTSemEventMultiSignal (m.queryInfoSem);
|
---|
| 815 | }
|
---|
| 816 | else
|
---|
| 817 | {
|
---|
| 818 | /* delete the semaphore ourselves */
|
---|
| 819 | RTSemEventMultiDestroy (m.queryInfoSem);
|
---|
| 820 | m.queryInfoSem = NIL_RTSEMEVENTMULTI;
|
---|
| 821 | }
|
---|
| 822 |
|
---|
| 823 | if (tempStateSet)
|
---|
| 824 | {
|
---|
| 825 | /* Set the proper state according to the result of the check */
|
---|
| 826 | if (success)
|
---|
| 827 | m.state = MediaState_Created;
|
---|
| 828 | else
|
---|
| 829 | m.state = MediaState_Inaccessible;
|
---|
| 830 | }
|
---|
| 831 | else
|
---|
| 832 | {
|
---|
| 833 | /* we're locked, use a special field to store the result */
|
---|
| 834 | m.accessibleInLock = success;
|
---|
| 835 | }
|
---|
| 836 |
|
---|
| 837 | return S_OK;
|
---|
| 838 | }
|
---|
| 839 |
|
---|
| 840 | /**
|
---|
| 841 | * Sets the extended error info according to the current media state.
|
---|
| 842 | *
|
---|
| 843 | * @note Must be called from under this object's write or read lock.
|
---|
| 844 | */
|
---|
| 845 | HRESULT MediumBase::setStateError()
|
---|
| 846 | {
|
---|
| 847 | HRESULT rc = E_FAIL;
|
---|
| 848 |
|
---|
| 849 | switch (m.state)
|
---|
| 850 | {
|
---|
| 851 | case MediaState_NotCreated:
|
---|
| 852 | {
|
---|
[15178] | 853 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 854 | tr ("Storage for the medium '%ls' is not created"),
|
---|
| 855 | m.locationFull.raw());
|
---|
| 856 | break;
|
---|
| 857 | }
|
---|
| 858 | case MediaState_Created:
|
---|
| 859 | {
|
---|
[15178] | 860 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 861 | tr ("Storage for the medium '%ls' is already created"),
|
---|
| 862 | m.locationFull.raw());
|
---|
| 863 | break;
|
---|
| 864 | }
|
---|
| 865 | case MediaState_LockedRead:
|
---|
| 866 | {
|
---|
[15178] | 867 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 868 | tr ("Medium '%ls' is locked for reading by another task"),
|
---|
| 869 | m.locationFull.raw());
|
---|
| 870 | break;
|
---|
| 871 | }
|
---|
| 872 | case MediaState_LockedWrite:
|
---|
| 873 | {
|
---|
[15178] | 874 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 875 | tr ("Medium '%ls' is locked for writing by another task"),
|
---|
| 876 | m.locationFull.raw());
|
---|
| 877 | break;
|
---|
| 878 | }
|
---|
| 879 | case MediaState_Inaccessible:
|
---|
| 880 | {
|
---|
[15215] | 881 | AssertMsg (!m.lastAccessError.isEmpty(),
|
---|
| 882 | ("There must always be a reason for Inaccessible"));
|
---|
| 883 |
|
---|
[13580] | 884 | /* be in sync with Console::powerUpThread() */
|
---|
| 885 | if (!m.lastAccessError.isEmpty())
|
---|
[15178] | 886 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 887 | tr ("Medium '%ls' is not accessible. %ls"),
|
---|
| 888 | m.locationFull.raw(), m.lastAccessError.raw());
|
---|
| 889 | else
|
---|
[15178] | 890 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 891 | tr ("Medium '%ls' is not accessible"),
|
---|
| 892 | m.locationFull.raw());
|
---|
| 893 | break;
|
---|
| 894 | }
|
---|
| 895 | case MediaState_Creating:
|
---|
| 896 | {
|
---|
[15178] | 897 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 898 | tr ("Storage for the medium '%ls' is being created"),
|
---|
| 899 | m.locationFull.raw(), m.lastAccessError.raw());
|
---|
| 900 | break;
|
---|
| 901 | }
|
---|
| 902 | case MediaState_Deleting:
|
---|
| 903 | {
|
---|
[15178] | 904 | rc = setError (VBOX_E_INVALID_OBJECT_STATE,
|
---|
[13580] | 905 | tr ("Storage for the medium '%ls' is being deleted"),
|
---|
| 906 | m.locationFull.raw(), m.lastAccessError.raw());
|
---|
| 907 | break;
|
---|
| 908 | }
|
---|
| 909 | default:
|
---|
| 910 | {
|
---|
| 911 | AssertFailed();
|
---|
| 912 | break;
|
---|
| 913 | }
|
---|
| 914 | }
|
---|
| 915 |
|
---|
| 916 | return rc;
|
---|
| 917 | }
|
---|
| 918 |
|
---|
| 919 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 920 | // ImageMediumBase class
|
---|
| 921 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 922 |
|
---|
| 923 | /**
|
---|
| 924 | * Initializes the image medium object by opening an image file at the specified
|
---|
| 925 | * location.
|
---|
| 926 | *
|
---|
| 927 | * @param aVirtualBox Parent VirtualBox object.
|
---|
| 928 | * @param aLocation Path to the image file (can be relative to the
|
---|
| 929 | * VirtualBox home directory).
|
---|
| 930 | * @param aId UUID of the image.
|
---|
| 931 | */
|
---|
[15051] | 932 | HRESULT ImageMediumBase::protectedInit (VirtualBox *aVirtualBox, CBSTR aLocation,
|
---|
[13580] | 933 | const Guid &aId)
|
---|
| 934 | {
|
---|
[13842] | 935 | LogFlowThisFunc (("aLocation='%ls', aId={%RTuuid}\n", aLocation, aId.raw()));
|
---|
[13580] | 936 |
|
---|
| 937 | AssertReturn (aVirtualBox, E_INVALIDARG);
|
---|
| 938 | AssertReturn (aLocation, E_INVALIDARG);
|
---|
| 939 | AssertReturn (!aId.isEmpty(), E_INVALIDARG);
|
---|
| 940 |
|
---|
| 941 | /* Enclose the state transition NotReady->InInit->Ready */
|
---|
| 942 | AutoInitSpan autoInitSpan (this);
|
---|
[14579] | 943 | AssertReturn (autoInitSpan.isOk(), E_FAIL);
|
---|
[13580] | 944 |
|
---|
| 945 | HRESULT rc = S_OK;
|
---|
| 946 |
|
---|
| 947 | /* share parent weakly */
|
---|
| 948 | unconst (mVirtualBox) = aVirtualBox;
|
---|
| 949 |
|
---|
| 950 | /* register with parent early, since uninit() will unconditionally
|
---|
| 951 | * unregister on failure */
|
---|
| 952 | mVirtualBox->addDependentChild (this);
|
---|
| 953 |
|
---|
| 954 | /* there must be a storage unit */
|
---|
| 955 | m.state = MediaState_Created;
|
---|
| 956 |
|
---|
| 957 | unconst (m.id) = aId;
|
---|
| 958 | rc = setLocation (aLocation);
|
---|
| 959 | CheckComRCReturnRC (rc);
|
---|
| 960 |
|
---|
| 961 | LogFlowThisFunc (("m.locationFull='%ls'\n", m.locationFull.raw()));
|
---|
| 962 |
|
---|
| 963 | /* get all the information about the medium from the file */
|
---|
| 964 | rc = queryInfo();
|
---|
| 965 | if (SUCCEEDED (rc))
|
---|
| 966 | {
|
---|
| 967 | /* if the image file is not accessible, it's not acceptable for the
|
---|
| 968 | * newly opened media so convert this into an error */
|
---|
| 969 | if (!m.lastAccessError.isNull())
|
---|
| 970 | rc = setError (E_FAIL, Utf8Str (m.lastAccessError));
|
---|
| 971 | }
|
---|
| 972 |
|
---|
| 973 | /* Confirm a successful initialization when it's the case */
|
---|
| 974 | if (SUCCEEDED (rc))
|
---|
| 975 | autoInitSpan.setSucceeded();
|
---|
| 976 |
|
---|
| 977 | return rc;
|
---|
| 978 | }
|
---|
| 979 |
|
---|
| 980 | /**
|
---|
| 981 | * Initializes the image medium object by loading its data from the given
|
---|
| 982 | * settings node.
|
---|
| 983 | *
|
---|
| 984 | * Note that it is assumed that this method is called only for registered media.
|
---|
| 985 | *
|
---|
| 986 | * @param aVirtualBox Parent VirtualBox object.
|
---|
| 987 | * @param aImageNode Either <DVDImage> or <FloppyImage> settings node.
|
---|
| 988 | */
|
---|
| 989 | HRESULT ImageMediumBase::protectedInit (VirtualBox *aVirtualBox,
|
---|
| 990 | const settings::Key &aImageNode)
|
---|
| 991 | {
|
---|
| 992 | AssertReturn (aVirtualBox, E_INVALIDARG);
|
---|
| 993 |
|
---|
| 994 | /* Enclose the state transition NotReady->InInit->Ready */
|
---|
| 995 | AutoInitSpan autoInitSpan (this);
|
---|
[14579] | 996 | AssertReturn (autoInitSpan.isOk(), E_FAIL);
|
---|
[13580] | 997 |
|
---|
| 998 | HRESULT rc = S_OK;
|
---|
| 999 |
|
---|
| 1000 | /* share parent weakly */
|
---|
| 1001 | unconst (mVirtualBox) = aVirtualBox;
|
---|
| 1002 |
|
---|
| 1003 | /* register with parent early, since uninit() will unconditionally
|
---|
| 1004 | * unregister on failure */
|
---|
| 1005 | mVirtualBox->addDependentChild (this);
|
---|
| 1006 |
|
---|
| 1007 | /* see below why we don't call queryInfo() (and therefore treat the medium
|
---|
| 1008 | * as inaccessible for now */
|
---|
| 1009 | m.state = MediaState_Inaccessible;
|
---|
| 1010 |
|
---|
| 1011 | /* required */
|
---|
| 1012 | unconst (m.id) = aImageNode.value <Guid> ("uuid");
|
---|
| 1013 | /* required */
|
---|
| 1014 | Bstr location = aImageNode.stringValue ("location");
|
---|
| 1015 | rc = setLocation (location);
|
---|
| 1016 | CheckComRCReturnRC (rc);
|
---|
| 1017 | /* optional */
|
---|
| 1018 | {
|
---|
| 1019 | settings::Key descNode = aImageNode.findKey ("Description");
|
---|
| 1020 | if (!descNode.isNull())
|
---|
| 1021 | m.description = descNode.keyStringValue();
|
---|
| 1022 | }
|
---|
| 1023 |
|
---|
[15124] | 1024 | LogFlowThisFunc (("m.locationFull='%ls', m.id={%RTuuid}\n",
|
---|
| 1025 | m.locationFull.raw(), m.id.raw()));
|
---|
[13580] | 1026 |
|
---|
| 1027 | /* Don't call queryInfo() for registered media to prevent the calling
|
---|
| 1028 | * thread (i.e. the VirtualBox server startup thread) from an unexpected
|
---|
| 1029 | * freeze but mark it as initially inaccessible instead. The vital UUID and
|
---|
| 1030 | * location properties are read from the registry file above; to get the
|
---|
[14294] | 1031 | * actual state and the rest of the data, the user will have to call
|
---|
[13580] | 1032 | * COMGETTER(State).*/
|
---|
| 1033 |
|
---|
| 1034 | /* Confirm a successful initialization when it's the case */
|
---|
| 1035 | if (SUCCEEDED (rc))
|
---|
| 1036 | autoInitSpan.setSucceeded();
|
---|
| 1037 |
|
---|
| 1038 | return rc;
|
---|
| 1039 | }
|
---|
| 1040 |
|
---|
| 1041 | /**
|
---|
| 1042 | * Uninitializes the instance.
|
---|
| 1043 | *
|
---|
| 1044 | * Called either from FinalRelease() or by the parent when it gets destroyed.
|
---|
| 1045 | */
|
---|
| 1046 | void ImageMediumBase::protectedUninit()
|
---|
| 1047 | {
|
---|
| 1048 | LogFlowThisFunc (("\n"));
|
---|
| 1049 |
|
---|
| 1050 | /* Enclose the state transition Ready->InUninit->NotReady */
|
---|
| 1051 | AutoUninitSpan autoUninitSpan (this);
|
---|
| 1052 | if (autoUninitSpan.uninitDone())
|
---|
| 1053 | return;
|
---|
| 1054 |
|
---|
| 1055 | mVirtualBox->removeDependentChild (this);
|
---|
| 1056 |
|
---|
| 1057 | unconst (mVirtualBox).setNull();
|
---|
| 1058 | }
|
---|
| 1059 |
|
---|
| 1060 | // public methods for internal purposes only
|
---|
| 1061 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 1062 |
|
---|
| 1063 | /**
|
---|
| 1064 | * Saves image data by appending a new <Image> child node to the
|
---|
| 1065 | * given <Images> parent node.
|
---|
| 1066 | *
|
---|
| 1067 | * @param aImagesNode <Images> node.
|
---|
| 1068 | *
|
---|
| 1069 | * @note Locks this object for reading.
|
---|
| 1070 | */
|
---|
| 1071 | HRESULT ImageMediumBase::saveSettings (settings::Key &aImagesNode)
|
---|
| 1072 | {
|
---|
| 1073 | using namespace settings;
|
---|
| 1074 |
|
---|
| 1075 | AssertReturn (!aImagesNode.isNull(), E_FAIL);
|
---|
| 1076 |
|
---|
| 1077 | AutoCaller autoCaller (this);
|
---|
| 1078 | CheckComRCReturnRC (autoCaller.rc());
|
---|
| 1079 |
|
---|
| 1080 | AutoReadLock alock (this);
|
---|
| 1081 |
|
---|
| 1082 | Key imageNode = aImagesNode.appendKey ("Image");
|
---|
| 1083 | /* required */
|
---|
| 1084 | imageNode.setValue <Guid> ("uuid", m.id);
|
---|
| 1085 | /* required */
|
---|
| 1086 | imageNode.setValue <Bstr> ("location", m.locationFull);
|
---|
| 1087 | /* optional */
|
---|
| 1088 | if (!m.description.isNull())
|
---|
| 1089 | {
|
---|
| 1090 | Key descNode = aImagesNode.createKey ("Description");
|
---|
| 1091 | descNode.setKeyValue <Bstr> (m.description);
|
---|
| 1092 | }
|
---|
| 1093 |
|
---|
| 1094 | return S_OK;
|
---|
| 1095 | }
|
---|
| 1096 |
|
---|
| 1097 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 1098 | // DVDImage2 class
|
---|
| 1099 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 1100 |
|
---|
| 1101 | DEFINE_EMPTY_CTOR_DTOR (DVDImage2)
|
---|
| 1102 |
|
---|
| 1103 | /**
|
---|
| 1104 | * @note Called from within this object's AutoMayUninitSpan and from under
|
---|
| 1105 | * mVirtualBox write lock.
|
---|
| 1106 | */
|
---|
| 1107 | HRESULT DVDImage2::unregisterWithVirtualBox()
|
---|
| 1108 | {
|
---|
| 1109 | return mVirtualBox->unregisterDVDImage (this);
|
---|
| 1110 | }
|
---|
| 1111 |
|
---|
| 1112 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 1113 | // FloppyImage2 class
|
---|
| 1114 | ////////////////////////////////////////////////////////////////////////////////
|
---|
| 1115 |
|
---|
| 1116 | DEFINE_EMPTY_CTOR_DTOR (FloppyImage2)
|
---|
| 1117 |
|
---|
| 1118 | /**
|
---|
| 1119 | * @note Called from within this object's AutoMayUninitSpan and from under
|
---|
| 1120 | * mVirtualBox write lock.
|
---|
| 1121 | */
|
---|
| 1122 | HRESULT FloppyImage2::unregisterWithVirtualBox()
|
---|
| 1123 | {
|
---|
| 1124 | return mVirtualBox->unregisterFloppyImage (this);
|
---|
| 1125 | }
|
---|
[14772] | 1126 | /* vi: set tabstop=4 shiftwidth=4 expandtab: */
|
---|