VirtualBox

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

Last change on this file since 13762 was 13580, checked in by vboxsync, 16 years ago

Ported s2 branch (r37120:38456).

  • 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 13580 2008-10-27 14:04:18Z 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_UNEXPECTED);
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_UNEXPECTED);
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_UNEXPECTED);
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}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use