VirtualBox

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

Last change on this file since 8861 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.3 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 "FloppyDriveImpl.h"
23#include "MachineImpl.h"
24#include "HostImpl.h"
25#include "HostFloppyDriveImpl.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 (FloppyDrive)
37
38HRESULT FloppyDrive::FinalConstruct()
39{
40 return S_OK;
41}
42
43void FloppyDrive::FinalRelease()
44{
45 uninit();
46}
47
48// public initializer/uninitializer for internal purposes only
49/////////////////////////////////////////////////////////////////////////////
50
51/**
52 * Initializes the Floppy drive object.
53 *
54 * @param aParent Handle of the parent object.
55 */
56HRESULT FloppyDrive::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 Floppy drive object given another Floppy 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 FloppyDrive::init (Machine *aParent, FloppyDrive *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 guest object given another guest 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 FloppyDrive::initCopy (Machine *aParent, FloppyDrive *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 FloppyDrive::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// IFloppyDrive properties
164/////////////////////////////////////////////////////////////////////////////
165
166STDMETHODIMP FloppyDrive::COMGETTER(Enabled) (BOOL *aEnabled)
167{
168 if (!aEnabled)
169 return E_POINTER;
170
171 AutoCaller autoCaller (this);
172 CheckComRCReturnRC (autoCaller.rc());
173
174 AutoReadLock alock (this);
175
176 *aEnabled = mData->mEnabled;
177
178 return S_OK;
179}
180
181STDMETHODIMP FloppyDrive::COMSETTER(Enabled) (BOOL aEnabled)
182{
183 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
184
185 AutoCaller autoCaller (this);
186 CheckComRCReturnRC (autoCaller.rc());
187
188 /* the machine needs to be mutable */
189 Machine::AutoMutableStateDependency adep (mParent);
190 CheckComRCReturnRC (adep.rc());
191
192 AutoWriteLock alock (this);
193
194 if (mData->mEnabled != aEnabled)
195 {
196 mData.backup();
197 mData->mEnabled = aEnabled;
198
199 /* leave the lock before informing callbacks */
200 alock.unlock();
201
202 mParent->onFloppyDriveChange();
203 }
204
205 return S_OK;
206}
207
208STDMETHODIMP FloppyDrive::COMGETTER(State) (DriveState_T *aDriveState)
209{
210 if (!aDriveState)
211 return E_POINTER;
212
213 AutoCaller autoCaller (this);
214 CheckComRCReturnRC (autoCaller.rc());
215
216 AutoReadLock alock (this);
217
218 *aDriveState = mData->mDriveState;
219
220 return S_OK;
221}
222
223// IFloppyDrive methods
224/////////////////////////////////////////////////////////////////////////////
225
226STDMETHODIMP FloppyDrive::MountImage (INPTR GUIDPARAM aImageId)
227{
228 if (Guid::isEmpty (aImageId))
229 return E_INVALIDARG;
230
231 AutoCaller autoCaller (this);
232 CheckComRCReturnRC (autoCaller.rc());
233
234 /* the machine needs to be mutable */
235 Machine::AutoMutableStateDependency adep (mParent);
236 CheckComRCReturnRC (adep.rc());
237
238 AutoWriteLock alock (this);
239
240 HRESULT rc = E_FAIL;
241
242 /* Our lifetime is bound to mParent's lifetime, so we don't add caller.
243 * We also don't lock mParent since its mParent field is const. */
244
245 ComPtr <IFloppyImage> image;
246 rc = mParent->virtualBox()->GetFloppyImage (aImageId, image.asOutParam());
247
248 if (SUCCEEDED (rc))
249 {
250 if (mData->mDriveState != DriveState_ImageMounted ||
251 !mData->mFloppyImage.equalsTo (image))
252 {
253 mData.backup();
254
255 unmount();
256
257 mData->mFloppyImage = image;
258 mData->mDriveState = DriveState_ImageMounted;
259
260 /* leave the lock before informing callbacks */
261 alock.unlock();
262
263 mParent->onFloppyDriveChange();
264 }
265 }
266
267 return rc;
268}
269
270STDMETHODIMP FloppyDrive::CaptureHostDrive (IHostFloppyDrive *aHostFloppyDrive)
271{
272 if (!aHostFloppyDrive)
273 return E_INVALIDARG;
274
275 AutoCaller autoCaller (this);
276 CheckComRCReturnRC (autoCaller.rc());
277
278 /* the machine needs to be mutable */
279 Machine::AutoMutableStateDependency adep (mParent);
280 CheckComRCReturnRC (adep.rc());
281
282 AutoWriteLock alock (this);
283
284 if (mData->mDriveState != DriveState_HostDriveCaptured ||
285 !mData->mHostDrive.equalsTo (aHostFloppyDrive))
286 {
287 mData.backup();
288
289 unmount();
290
291 mData->mHostDrive = aHostFloppyDrive;
292 mData->mDriveState = DriveState_HostDriveCaptured;
293
294 /* leave the lock before informing callbacks */
295 alock.unlock();
296
297 mParent->onFloppyDriveChange();
298 }
299
300 return S_OK;
301}
302
303STDMETHODIMP FloppyDrive::Unmount()
304{
305 AutoCaller autoCaller (this);
306 CheckComRCReturnRC (autoCaller.rc());
307
308 /* the machine needs to be mutable */
309 Machine::AutoMutableStateDependency adep (mParent);
310 CheckComRCReturnRC (adep.rc());
311
312 AutoWriteLock alock (this);
313
314 if (mData->mDriveState != DriveState_NotMounted)
315 {
316 mData.backup();
317
318 unmount();
319
320 mData->mDriveState = DriveState_NotMounted;
321
322 /* leave the lock before informing callbacks */
323 alock.unlock();
324
325 mParent->onFloppyDriveChange();
326 }
327
328 return S_OK;
329}
330
331STDMETHODIMP FloppyDrive::GetImage (IFloppyImage **aFloppyImage)
332{
333 if (!aFloppyImage)
334 return E_POINTER;
335
336 AutoCaller autoCaller (this);
337 CheckComRCReturnRC (autoCaller.rc());
338
339 AutoReadLock alock (this);
340
341 mData->mFloppyImage.queryInterfaceTo (aFloppyImage);
342
343 return S_OK;
344}
345
346STDMETHODIMP FloppyDrive::GetHostDrive (IHostFloppyDrive **aHostDrive)
347{
348 if (!aHostDrive)
349 return E_POINTER;
350
351 AutoCaller autoCaller (this);
352 CheckComRCReturnRC (autoCaller.rc());
353
354 AutoReadLock alock (this);
355
356 mData->mHostDrive.queryInterfaceTo (aHostDrive);
357
358 return S_OK;
359}
360
361// public methods only for internal purposes
362/////////////////////////////////////////////////////////////////////////////
363
364/**
365 * Loads settings from the given machine node.
366 * May be called once right after this object creation.
367 *
368 * @param aMachineNode <Machine> node.
369 *
370 * @note Locks this object for writing.
371 */
372HRESULT FloppyDrive::loadSettings (const settings::Key &aMachineNode)
373{
374 using namespace settings;
375
376 AssertReturn (!aMachineNode.isNull(), E_FAIL);
377
378 AutoCaller autoCaller (this);
379 AssertComRCReturnRC (autoCaller.rc());
380
381 AutoWriteLock alock (this);
382
383 /* Note: we assume that the default values for attributes of optional
384 * nodes are assigned in the Data::Data() constructor and don't do it
385 * here. It implies that this method may only be called after constructing
386 * a new BIOSSettings object while all its data fields are in the default
387 * values. Exceptions are fields whose creation time defaults don't match
388 * values that should be applied when these fields are not explicitly set
389 * in the settings file (for backwards compatibility reasons). This takes
390 * place when a setting of a newly created object must default to A while
391 * the same setting of an object loaded from the old settings file must
392 * default to B. */
393
394 HRESULT rc = S_OK;
395
396 /* Floppy drive (required, contains either Image or HostDrive or nothing) */
397 Key floppyDriveNode = aMachineNode.key ("FloppyDrive");
398
399 /* optional, defaults to true */
400 mData->mEnabled = floppyDriveNode.value <bool> ("enabled");
401
402 Key typeNode;
403
404 if (!(typeNode = floppyDriveNode.findKey ("Image")).isNull())
405 {
406 Guid uuid = typeNode.value <Guid> ("uuid");
407 rc = MountImage (uuid);
408 CheckComRCReturnRC (rc);
409 }
410 else if (!(typeNode = floppyDriveNode.findKey ("HostDrive")).isNull())
411 {
412
413 Bstr src = typeNode.stringValue ("src");
414
415 /* find the correspoding object */
416 ComObjPtr <Host> host = mParent->virtualBox()->host();
417
418 ComPtr <IHostFloppyDriveCollection> coll;
419 rc = host->COMGETTER(FloppyDrives) (coll.asOutParam());
420 AssertComRC (rc);
421
422 ComPtr <IHostFloppyDrive> drive;
423 rc = coll->FindByName (src, drive.asOutParam());
424 if (SUCCEEDED (rc))
425 {
426 rc = CaptureHostDrive (drive);
427 CheckComRCReturnRC (rc);
428 }
429 else if (rc == E_INVALIDARG)
430 {
431 /* the host DVD drive is not currently available. we
432 * assume it will be available later and create an
433 * extra object now */
434 ComObjPtr <HostFloppyDrive> hostDrive;
435 hostDrive.createObject();
436 rc = hostDrive->init (src);
437 AssertComRC (rc);
438 rc = CaptureHostDrive (hostDrive);
439 CheckComRCReturnRC (rc);
440 }
441 else
442 AssertComRC (rc);
443 }
444
445 return S_OK;
446}
447
448/**
449 * Saves settings to the given machine node.
450 *
451 * @param aMachineNode <Machine> node.
452 *
453 * @note Locks this object for reading.
454 */
455HRESULT FloppyDrive::saveSettings (settings::Key &aMachineNode)
456{
457 using namespace settings;
458
459 AssertReturn (!aMachineNode.isNull(), E_FAIL);
460
461 AutoCaller autoCaller (this);
462 AssertComRCReturnRC (autoCaller.rc());
463
464 AutoReadLock alock (this);
465
466 Key node = aMachineNode.createKey ("FloppyDrive");
467
468 node.setValue <bool> ("enabled", !!mData->mEnabled);
469
470 switch (mData->mDriveState)
471 {
472 case DriveState_ImageMounted:
473 {
474 Assert (!mData->mFloppyImage.isNull());
475
476 Guid id;
477 HRESULT rc = mData->mFloppyImage->COMGETTER(Id) (id.asOutParam());
478 AssertComRC (rc);
479 Assert (!id.isEmpty());
480
481 Key imageNode = node.createKey ("Image");
482 imageNode.setValue <Guid> ("uuid", id);
483 break;
484 }
485 case DriveState_HostDriveCaptured:
486 {
487 Assert (!mData->mHostDrive.isNull());
488
489 Bstr name;
490 HRESULT rc = mData->mHostDrive->COMGETTER(Name) (name.asOutParam());
491 AssertComRC (rc);
492 Assert (!name.isEmpty());
493
494 Key hostDriveNode = node.createKey ("HostDrive");
495 hostDriveNode.setValue <Bstr> ("src", name);
496 break;
497 }
498 case DriveState_NotMounted:
499 /* do nothing, i.e.leave the drive node empty */
500 break;
501 default:
502 ComAssertMsgFailedRet (("Invalid drive state: %d\n",
503 mData->mDriveState),
504 E_FAIL);
505 }
506
507 return S_OK;
508}
509
510/**
511 * @note Locks this object for writing.
512 */
513bool FloppyDrive::rollback()
514{
515 /* sanity */
516 AutoCaller autoCaller (this);
517 AssertComRCReturn (autoCaller.rc(), false);
518
519 AutoWriteLock alock (this);
520
521 bool changed = false;
522
523 if (mData.isBackedUp())
524 {
525 /* we need to check all data to see whether anything will be changed
526 * after rollback */
527 changed = mData.hasActualChanges();
528 mData.rollback();
529 }
530
531 return changed;
532}
533
534/**
535 * @note Locks this object for writing, together with the peer object (also
536 * for writing) if there is one.
537 */
538void FloppyDrive::commit()
539{
540 /* sanity */
541 AutoCaller autoCaller (this);
542 AssertComRCReturnVoid (autoCaller.rc());
543
544 /* sanity too */
545 AutoCaller peerCaller (mPeer);
546 AssertComRCReturnVoid (peerCaller.rc());
547
548 /* lock both for writing since we modify both (mPeer is "master" so locked
549 * first) */
550 AutoMultiWriteLock2 alock (mPeer, this);
551
552 if (mData.isBackedUp())
553 {
554 mData.commit();
555 if (mPeer)
556 {
557 /* attach new data to the peer and reshare it */
558 mPeer->mData.attach (mData);
559 }
560 }
561}
562
563/**
564 * @note Locks this object for writing, together with the peer object (locked
565 * for reading) if there is one.
566 */
567void FloppyDrive::copyFrom (FloppyDrive *aThat)
568{
569 /* sanity */
570 AutoCaller autoCaller (this);
571 AssertComRCReturnVoid (autoCaller.rc());
572
573 /* sanity too */
574 AutoCaller thatCaller (aThat);
575 AssertComRCReturnVoid (thatCaller.rc());
576
577 /* peer is not modified, lock it for reading (aThat is "master" so locked
578 * first) */
579 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
580
581 /* this will back up current data */
582 mData.assignCopy (aThat->mData);
583}
584
585// private methods
586/////////////////////////////////////////////////////////////////////////////
587
588/**
589 * Helper to unmount a drive.
590 *
591 * @return COM status code
592 */
593HRESULT FloppyDrive::unmount()
594{
595 AssertReturn (isWriteLockOnCurrentThread(), E_FAIL);
596
597 if (mData->mFloppyImage)
598 mData->mFloppyImage.setNull();
599 if (mData->mHostDrive)
600 mData->mHostDrive.setNull();
601
602 return S_OK;
603}
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