VirtualBox

source: vbox/trunk/src/VBox/Main/FloppyDriveImpl.cpp@ 14953

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