VirtualBox

source: vbox/trunk/src/VBox/Main/DVDDriveImpl.cpp@ 10420

Last change on this file since 10420 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: 15.1 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 "DVDDriveImpl.h"
23#include "MachineImpl.h"
24#include "HostImpl.h"
25#include "HostDVDDriveImpl.h"
26#include "VirtualBoxImpl.h"
27
28#include "Logging.h"
29
30#include <iprt/string.h>
31#include <iprt/cpputils.h>
32
33// constructor / destructor
34////////////////////////////////////////////////////////////////////////////////
35
36DEFINE_EMPTY_CTOR_DTOR (DVDDrive)
37
38HRESULT DVDDrive::FinalConstruct()
39{
40 return S_OK;
41}
42
43void DVDDrive::FinalRelease()
44{
45 uninit();
46}
47
48// public initializer/uninitializer for internal purposes only
49////////////////////////////////////////////////////////////////////////////////
50
51/**
52 * Initializes the DVD drive object.
53 *
54 * @param aParent Handle of the parent object.
55 */
56HRESULT DVDDrive::init (Machine *aParent)
57{
58 LogFlowThisFunc (("aParent=%p\n", aParent));
59
60 ComAssertRet (aParent, E_INVALIDARG);
61
62 /* Enclose the state transition NotReady->InInit->Ready */
63 AutoInitSpan autoInitSpan (this);
64 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
65
66 unconst (mParent) = aParent;
67 /* mPeer is left null */
68
69 mData.allocate();
70
71 /* Confirm a successful initialization */
72 autoInitSpan.setSucceeded();
73
74 return S_OK;
75}
76
77/**
78 * Initializes the DVD drive object given another DVD drive object
79 * (a kind of copy constructor). This object shares data with
80 * the object passed as an argument.
81 *
82 * @note This object must be destroyed before the original object
83 * it shares data with is destroyed.
84 *
85 * @note Locks @a aThat object for reading.
86 */
87HRESULT DVDDrive::init (Machine *aParent, DVDDrive *aThat)
88{
89 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
90
91 ComAssertRet (aParent && aThat, E_INVALIDARG);
92
93 /* Enclose the state transition NotReady->InInit->Ready */
94 AutoInitSpan autoInitSpan (this);
95 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
96
97 unconst (mParent) = aParent;
98 unconst (mPeer) = aThat;
99
100 AutoCaller thatCaller (aThat);
101 AssertComRCReturnRC (thatCaller.rc());
102
103 AutoReadLock thatLock (aThat);
104 mData.share (aThat->mData);
105
106 /* Confirm a successful initialization */
107 autoInitSpan.setSucceeded();
108
109 return S_OK;
110}
111
112/**
113 * Initializes the DVD drive object given another DVD drive object
114 * (a kind of copy constructor). This object makes a private copy of data
115 * of the original object passed as an argument.
116 *
117 * @note Locks @a aThat object for reading.
118 */
119HRESULT DVDDrive::initCopy (Machine *aParent, DVDDrive *aThat)
120{
121 LogFlowThisFunc (("aParent=%p, aThat=%p\n", aParent, aThat));
122
123 ComAssertRet (aParent && aThat, E_INVALIDARG);
124
125 /* Enclose the state transition NotReady->InInit->Ready */
126 AutoInitSpan autoInitSpan (this);
127 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
128
129 unconst (mParent) = aParent;
130 /* mPeer is left null */
131
132 AutoCaller thatCaller (aThat);
133 AssertComRCReturnRC (thatCaller.rc());
134
135 AutoReadLock thatLock (aThat);
136 mData.attachCopy (aThat->mData);
137
138 /* Confirm a successful initialization */
139 autoInitSpan.setSucceeded();
140
141 return S_OK;
142}
143
144/**
145 * Uninitializes the instance and sets the ready flag to FALSE.
146 * Called either from FinalRelease() or by the parent when it gets destroyed.
147 */
148void DVDDrive::uninit()
149{
150 LogFlowThisFunc (("\n"));
151
152 /* Enclose the state transition Ready->InUninit->NotReady */
153 AutoUninitSpan autoUninitSpan (this);
154 if (autoUninitSpan.uninitDone())
155 return;
156
157 mData.free();
158
159 unconst (mPeer).setNull();
160 unconst (mParent).setNull();
161}
162
163// IDVDDrive properties
164////////////////////////////////////////////////////////////////////////////////
165
166STDMETHODIMP DVDDrive::COMGETTER(State) (DriveState_T *aDriveState)
167{
168 if (!aDriveState)
169 return E_POINTER;
170
171 AutoCaller autoCaller (this);
172 CheckComRCReturnRC (autoCaller.rc());
173
174 AutoReadLock alock (this);
175
176 *aDriveState = mData->mDriveState;
177
178 return S_OK;
179}
180
181STDMETHODIMP DVDDrive::COMGETTER(Passthrough) (BOOL *aPassthrough)
182{
183 if (!aPassthrough)
184 return E_POINTER;
185
186 AutoCaller autoCaller (this);
187 CheckComRCReturnRC (autoCaller.rc());
188
189 AutoReadLock alock (this);
190
191 *aPassthrough = mData->mPassthrough;
192
193 return S_OK;
194}
195
196STDMETHODIMP DVDDrive::COMSETTER(Passthrough) (BOOL aPassthrough)
197{
198 AutoCaller autoCaller (this);
199 CheckComRCReturnRC (autoCaller.rc());
200
201 /* the machine needs to be mutable */
202 Machine::AutoMutableStateDependency adep (mParent);
203 CheckComRCReturnRC (adep.rc());
204
205 AutoWriteLock alock (this);
206
207 if (mData->mPassthrough != aPassthrough)
208 {
209 mData.backup();
210 mData->mPassthrough = aPassthrough;
211 }
212
213 return S_OK;
214}
215
216// IDVDDrive methods
217////////////////////////////////////////////////////////////////////////////////
218
219STDMETHODIMP DVDDrive::MountImage (INPTR GUIDPARAM aImageId)
220{
221 if (Guid::isEmpty (aImageId))
222 return E_INVALIDARG;
223
224 AutoCaller autoCaller (this);
225 CheckComRCReturnRC (autoCaller.rc());
226
227 /* the machine needs to be mutable */
228 Machine::AutoMutableStateDependency adep (mParent);
229 CheckComRCReturnRC (adep.rc());
230
231 AutoWriteLock alock (this);
232
233 HRESULT rc = E_FAIL;
234
235 /* Our lifetime is bound to mParent's lifetime, so we don't add caller.
236 * We also don't lock mParent since its mParent field is const. */
237
238 ComPtr <IDVDImage> image;
239 rc = mParent->virtualBox()->GetDVDImage (aImageId, image.asOutParam());
240
241 if (SUCCEEDED (rc))
242 {
243 if (mData->mDriveState != DriveState_ImageMounted ||
244 !mData->mDVDImage.equalsTo (image))
245 {
246 mData.backup();
247
248 unmount();
249
250 mData->mDVDImage = image;
251 mData->mDriveState = DriveState_ImageMounted;
252
253 /* leave the lock before informing callbacks */
254 alock.unlock();
255
256 mParent->onDVDDriveChange();
257 }
258 }
259
260 return rc;
261}
262
263STDMETHODIMP DVDDrive::CaptureHostDrive (IHostDVDDrive *aHostDVDDrive)
264{
265 if (!aHostDVDDrive)
266 return E_INVALIDARG;
267
268 AutoCaller autoCaller (this);
269 CheckComRCReturnRC (autoCaller.rc());
270
271 /* the machine needs to be mutable */
272 Machine::AutoMutableStateDependency adep (mParent);
273 CheckComRCReturnRC (adep.rc());
274
275 AutoWriteLock alock (this);
276
277 if (mData->mDriveState != DriveState_HostDriveCaptured ||
278 !mData->mHostDrive.equalsTo (aHostDVDDrive))
279 {
280 mData.backup();
281
282 unmount();
283
284 mData->mHostDrive = aHostDVDDrive;
285 mData->mDriveState = DriveState_HostDriveCaptured;
286
287 /* leave the lock before informing callbacks */
288 alock.unlock();
289
290 mParent->onDVDDriveChange();
291 }
292
293 return S_OK;
294}
295
296STDMETHODIMP DVDDrive::Unmount()
297{
298 AutoCaller autoCaller (this);
299 CheckComRCReturnRC (autoCaller.rc());
300
301 /* the machine needs to be mutable */
302 Machine::AutoMutableStateDependency adep (mParent);
303 CheckComRCReturnRC (adep.rc());
304
305 AutoWriteLock alock (this);
306
307 if (mData->mDriveState != DriveState_NotMounted)
308 {
309 mData.backup();
310
311 unmount();
312
313 mData->mDriveState = DriveState_NotMounted;
314
315 /* leave the lock before informing callbacks */
316 alock.unlock();
317
318 mParent->onDVDDriveChange();
319 }
320
321 return S_OK;
322}
323
324STDMETHODIMP DVDDrive::GetImage (IDVDImage **aDVDImage)
325{
326 if (!aDVDImage)
327 return E_POINTER;
328
329 AutoCaller autoCaller (this);
330 CheckComRCReturnRC (autoCaller.rc());
331
332 AutoReadLock alock (this);
333
334 mData->mDVDImage.queryInterfaceTo (aDVDImage);
335
336 return S_OK;
337}
338
339STDMETHODIMP DVDDrive::GetHostDrive(IHostDVDDrive **aHostDrive)
340{
341 if (!aHostDrive)
342 return E_POINTER;
343
344 AutoCaller autoCaller (this);
345 CheckComRCReturnRC (autoCaller.rc());
346
347 AutoReadLock alock (this);
348
349 mData->mHostDrive.queryInterfaceTo (aHostDrive);
350
351 return S_OK;
352}
353
354// public methods only for internal purposes
355////////////////////////////////////////////////////////////////////////////////
356
357/**
358 * Loads settings from the given machine node.
359 * May be called once right after this object creation.
360 *
361 * @param aMachineNode <Machine> node.
362 *
363 * @note Locks this object for writing.
364 */
365HRESULT DVDDrive::loadSettings (const settings::Key &aMachineNode)
366{
367 using namespace settings;
368
369 AssertReturn (!aMachineNode.isNull(), E_FAIL);
370
371 AutoCaller autoCaller (this);
372 AssertComRCReturnRC (autoCaller.rc());
373
374 AutoWriteLock alock (this);
375
376 /* Note: we assume that the default values for attributes of optional
377 * nodes are assigned in the Data::Data() constructor and don't do it
378 * here. It implies that this method may only be called after constructing
379 * a new BIOSSettings object while all its data fields are in the default
380 * values. Exceptions are fields whose creation time defaults don't match
381 * values that should be applied when these fields are not explicitly set
382 * in the settings file (for backwards compatibility reasons). This takes
383 * place when a setting of a newly created object must default to A while
384 * the same setting of an object loaded from the old settings file must
385 * default to B. */
386
387 HRESULT rc = S_OK;
388
389 /* DVD drive (required, contains either Image or HostDrive or nothing) */
390 Key dvdDriveNode = aMachineNode.key ("DVDDrive");
391
392 /* optional, defaults to false */
393 mData->mPassthrough = dvdDriveNode.value <bool> ("passthrough");
394
395 Key typeNode;
396
397 if (!(typeNode = dvdDriveNode.findKey ("Image")).isNull())
398 {
399 Guid uuid = typeNode.value <Guid> ("uuid");
400 rc = MountImage (uuid);
401 CheckComRCReturnRC (rc);
402 }
403 else if (!(typeNode = dvdDriveNode.findKey ("HostDrive")).isNull())
404 {
405
406 Bstr src = typeNode.stringValue ("src");
407
408 /* find the correspoding object */
409 ComObjPtr <Host> host = mParent->virtualBox()->host();
410
411 ComPtr <IHostDVDDriveCollection> coll;
412 rc = host->COMGETTER(DVDDrives) (coll.asOutParam());
413 AssertComRC (rc);
414
415 ComPtr <IHostDVDDrive> drive;
416 rc = coll->FindByName (src, drive.asOutParam());
417 if (SUCCEEDED (rc))
418 {
419 rc = CaptureHostDrive (drive);
420 CheckComRCReturnRC (rc);
421 }
422 else if (rc == E_INVALIDARG)
423 {
424 /* the host DVD drive is not currently available. we
425 * assume it will be available later and create an
426 * extra object now */
427 ComObjPtr <HostDVDDrive> hostDrive;
428 hostDrive.createObject();
429 rc = hostDrive->init (src);
430 AssertComRC (rc);
431 rc = CaptureHostDrive (hostDrive);
432 CheckComRCReturnRC (rc);
433 }
434 else
435 AssertComRC (rc);
436 }
437
438 return S_OK;
439}
440
441/**
442 * Saves settings to the given machine node.
443 *
444 * @param aMachineNode <Machine> node.
445 *
446 * @note Locks this object for reading.
447 */
448HRESULT DVDDrive::saveSettings (settings::Key &aMachineNode)
449{
450 using namespace settings;
451
452 AssertReturn (!aMachineNode.isNull(), E_FAIL);
453
454 AutoCaller autoCaller (this);
455 AssertComRCReturnRC (autoCaller.rc());
456
457 AutoReadLock alock (this);
458
459 Key node = aMachineNode.createKey ("DVDDrive");
460
461 node.setValue <bool> ("passthrough", !!mData->mPassthrough);
462
463 switch (mData->mDriveState)
464 {
465 case DriveState_ImageMounted:
466 {
467 Assert (!mData->mDVDImage.isNull());
468
469 Guid id;
470 HRESULT rc = mData->mDVDImage->COMGETTER(Id) (id.asOutParam());
471 AssertComRC (rc);
472 Assert (!id.isEmpty());
473
474 Key imageNode = node.createKey ("Image");
475 imageNode.setValue <Guid> ("uuid", id);
476 break;
477 }
478 case DriveState_HostDriveCaptured:
479 {
480 Assert (!mData->mHostDrive.isNull());
481
482 Bstr name;
483 HRESULT rc = mData->mHostDrive->COMGETTER(Name) (name.asOutParam());
484 AssertComRC (rc);
485 Assert (!name.isEmpty());
486
487 Key hostDriveNode = node.createKey ("HostDrive");
488 hostDriveNode.setValue <Bstr> ("src", name);
489 break;
490 }
491 case DriveState_NotMounted:
492 /* do nothing, i.e.leave the drive node empty */
493 break;
494 default:
495 ComAssertMsgFailedRet (("Invalid drive state: %d\n",
496 mData->mDriveState),
497 E_FAIL);
498 }
499
500 return S_OK;
501}
502
503/**
504 * @note Locks this object for writing.
505 */
506bool DVDDrive::rollback()
507{
508 /* sanity */
509 AutoCaller autoCaller (this);
510 AssertComRCReturn (autoCaller.rc(), false);
511
512 AutoWriteLock alock (this);
513
514 bool changed = false;
515
516 if (mData.isBackedUp())
517 {
518 /* we need to check all data to see whether anything will be changed
519 * after rollback */
520 changed = mData.hasActualChanges();
521 mData.rollback();
522 }
523
524 return changed;
525}
526
527/**
528 * @note Locks this object for writing, together with the peer object (also
529 * for writing) if there is one.
530 */
531void DVDDrive::commit()
532{
533 /* sanity */
534 AutoCaller autoCaller (this);
535 AssertComRCReturnVoid (autoCaller.rc());
536
537 /* sanity too */
538 AutoCaller peerCaller (mPeer);
539 AssertComRCReturnVoid (peerCaller.rc());
540
541 /* lock both for writing since we modify both (mPeer is "master" so locked
542 * first) */
543 AutoMultiWriteLock2 alock (mPeer, this);
544
545 if (mData.isBackedUp())
546 {
547 mData.commit();
548 if (mPeer)
549 {
550 /* attach new data to the peer and reshare it */
551 mPeer->mData.attach (mData);
552 }
553 }
554}
555
556/**
557 * @note Locks this object for writing, together with the peer object
558 * represented by @a aThat (locked for reading).
559 */
560void DVDDrive::copyFrom (DVDDrive *aThat)
561{
562 AssertReturnVoid (aThat != NULL);
563
564 /* sanity */
565 AutoCaller autoCaller (this);
566 AssertComRCReturnVoid (autoCaller.rc());
567
568 /* sanity too */
569 AutoCaller thatCaller (aThat);
570 AssertComRCReturnVoid (thatCaller.rc());
571
572 /* peer is not modified, lock it for reading (aThat is "master" so locked
573 * first) */
574 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
575
576 /* this will back up current data */
577 mData.assignCopy (aThat->mData);
578}
579
580// private methods
581////////////////////////////////////////////////////////////////////////////////
582
583/**
584 * Helper to unmount a drive.
585 *
586 * @return COM status code
587 *
588 */
589HRESULT DVDDrive::unmount()
590{
591 AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
592
593 if (mData->mDVDImage)
594 mData->mDVDImage.setNull();
595 if (mData->mHostDrive)
596 mData->mHostDrive.setNull();
597
598 return S_OK;
599}
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