VirtualBox

source: vbox/trunk/src/VBox/Main/USBDeviceFilterImpl.cpp@ 33000

Last change on this file since 33000 was 32718, checked in by vboxsync, 14 years ago

com/string: Remove bool conversion operator and other convenience error operators. They are hiding programming errors (like incorrect empty string checks, and in one case a free of the wrong pointer).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.7 KB
Line 
1/* $Id: USBDeviceFilterImpl.cpp 32718 2010-09-23 12:57:52Z vboxsync $ */
2/** @file
3 * Implementation of VirtualBox COM components: USBDeviceFilter and HostUSBDeviceFilter
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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
18#include "USBDeviceFilterImpl.h"
19#include "USBControllerImpl.h"
20#include "MachineImpl.h"
21#include "HostImpl.h"
22
23#include <iprt/cpp/utils.h>
24#include <VBox/settings.h>
25
26#include "AutoStateDep.h"
27#include "AutoCaller.h"
28#include "Logging.h"
29
30////////////////////////////////////////////////////////////////////////////////
31// Internal Helpers
32////////////////////////////////////////////////////////////////////////////////
33
34/**
35 * Converts a USBFilter field into a string.
36 *
37 * (This function is also used by HostUSBDeviceFilter.)
38 *
39 * @param aFilter The filter.
40 * @param aIdx The field index.
41 * @param aStr The output string.
42 */
43static void usbFilterFieldToString(PCUSBFILTER aFilter, USBFILTERIDX aIdx, Utf8Str &out)
44{
45 const USBFILTERMATCH matchingMethod = USBFilterGetMatchingMethod(aFilter, aIdx);
46 Assert(matchingMethod != USBFILTERMATCH_INVALID);
47
48 if (USBFilterIsMethodNumeric(matchingMethod))
49 {
50 int value = USBFilterGetNum(aFilter, aIdx);
51 Assert(value >= 0 && value <= 0xffff);
52
53 out = Utf8StrFmt("%04RX16", (uint16_t)value);
54 }
55 else if (USBFilterIsMethodString(matchingMethod))
56 {
57 out = USBFilterGetString(aFilter, aIdx);
58 }
59 else
60 out.setNull();
61}
62
63/*static*/
64const char* USBDeviceFilter::describeUSBFilterIdx(USBFILTERIDX aIdx)
65{
66 switch (aIdx)
67 {
68 case USBFILTERIDX_VENDOR_ID: return tr("Vendor ID");
69 case USBFILTERIDX_PRODUCT_ID: return tr("Product ID");
70 case USBFILTERIDX_DEVICE: return tr("Revision");
71 case USBFILTERIDX_MANUFACTURER_STR: return tr("Manufacturer");
72 case USBFILTERIDX_PRODUCT_STR: return tr("Product");
73 case USBFILTERIDX_SERIAL_NUMBER_STR: return tr("Serial number");
74 case USBFILTERIDX_PORT: return tr("Port number");
75 default: return "";
76 }
77 return "";
78}
79
80/**
81 * Interprets a string and assigns it to a USBFilter field.
82 *
83 * (This function is also used by HostUSBDeviceFilter.)
84 *
85 * @param aFilter The filter.
86 * @param aIdx The field index.
87 * @param aStr The input string.
88 * @param aName The field name for use in the error string.
89 * @param aErrStr Where to return the error string on failure.
90 *
91 * @return COM status code.
92 * @remark The idea was to have this as a static function, but tr() doesn't wanna work without a class :-/
93 */
94/*static*/ HRESULT USBDeviceFilter::usbFilterFieldFromString(PUSBFILTER aFilter,
95 USBFILTERIDX aIdx,
96 const Utf8Str &aValue,
97 Utf8Str &aErrStr)
98{
99 int vrc;
100// Utf8Str str (aStr);
101 if (aValue.isEmpty())
102 vrc = USBFilterSetIgnore(aFilter, aIdx);
103 else
104 {
105 const char *pcszValue = aValue.c_str();
106 if (USBFilterIsNumericField(aIdx))
107 {
108 /* Is it a lonely number? */
109 char *pszNext;
110 uint64_t u64;
111 vrc = RTStrToUInt64Ex(pcszValue, &pszNext, 16, &u64);
112 if (RT_SUCCESS(vrc))
113 pszNext = RTStrStripL (pszNext);
114 if ( vrc == VINF_SUCCESS
115 && !*pszNext)
116 {
117 if (u64 > 0xffff)
118 {
119 // there was a bug writing out "-1" values in earlier versions, which got
120 // written as "FFFFFFFF"; make sure we don't fail on those
121 if (u64 == 0xffffffff)
122 u64 = 0xffff;
123 else
124 {
125 aErrStr = Utf8StrFmt(tr("The %s value '%s' is too big (max 0xFFFF)"), describeUSBFilterIdx(aIdx), pcszValue);
126 return E_INVALIDARG;
127 }
128 }
129
130 vrc = USBFilterSetNumExact(aFilter, aIdx, (uint16_t)u64, true /* fMustBePresent */);
131 }
132 else
133 vrc = USBFilterSetNumExpression(aFilter, aIdx, pcszValue, true /* fMustBePresent */);
134 }
135 else
136 {
137 /* Any wildcard in the string? */
138 Assert(USBFilterIsStringField(aIdx));
139 if ( strchr(pcszValue, '*')
140 || strchr(pcszValue, '?')
141 /* || strchr (psz, '[') - later */
142 )
143 vrc = USBFilterSetStringPattern(aFilter, aIdx, pcszValue, true /* fMustBePresent */);
144 else
145 vrc = USBFilterSetStringExact(aFilter, aIdx, pcszValue, true /* fMustBePresent */);
146 }
147 }
148
149 if (RT_FAILURE(vrc))
150 {
151 if (vrc == VERR_INVALID_PARAMETER)
152 {
153 aErrStr = Utf8StrFmt(tr("The %s filter expression '%s' is not valid"), describeUSBFilterIdx(aIdx), aValue.c_str());
154 return E_INVALIDARG;
155 }
156 if (vrc == VERR_BUFFER_OVERFLOW)
157 {
158 aErrStr = Utf8StrFmt(tr("Insufficient expression space for the '%s' filter expression '%s'"), describeUSBFilterIdx(aIdx), aValue.c_str());
159 return E_FAIL;
160 }
161 AssertRC(vrc);
162 aErrStr = Utf8StrFmt(tr("Encountered unexpected status %Rrc when setting '%s' to '%s'"), vrc, describeUSBFilterIdx(aIdx), aValue.c_str());
163 return E_FAIL;
164 }
165
166 return S_OK;
167}
168
169
170////////////////////////////////////////////////////////////////////////////////
171// USBDeviceFilter
172////////////////////////////////////////////////////////////////////////////////
173
174// constructor / destructor
175////////////////////////////////////////////////////////////////////////////////
176
177USBDeviceFilter::USBDeviceFilter()
178 : mParent(NULL),
179 mPeer(NULL)
180{
181}
182
183USBDeviceFilter::~USBDeviceFilter()
184{
185}
186
187HRESULT USBDeviceFilter::FinalConstruct()
188{
189 return S_OK;
190}
191
192void USBDeviceFilter::FinalRelease()
193{
194 uninit();
195}
196
197// public initializer/uninitializer for internal purposes only
198////////////////////////////////////////////////////////////////////////////////
199
200/**
201 * Initializes the USB device filter object.
202 *
203 * @param aParent Handle of the parent object.
204 */
205HRESULT USBDeviceFilter::init(USBController *aParent,
206 const settings::USBDeviceFilter &data)
207{
208 LogFlowThisFunc(("aParent=%p\n", aParent));
209
210 ComAssertRet(aParent && !data.strName.isEmpty(), E_INVALIDARG);
211
212 /* Enclose the state transition NotReady->InInit->Ready */
213 AutoInitSpan autoInitSpan(this);
214 AssertReturn(autoInitSpan.isOk(), E_FAIL);
215
216 unconst(mParent) = aParent;
217 /* mPeer is left null */
218
219 m_fModified = false;
220
221 mData.allocate();
222 mData->mName = data.strName;
223 mData->mActive = data.fActive;
224 mData->mMaskedIfs = 0;
225
226 /* initialize all filters to any match using null string */
227 USBFilterInit(&mData->mUSBFilter, USBFILTERTYPE_CAPTURE);
228 mData->mRemote = NULL;
229
230 mInList = false;
231
232 /* use setters for the attributes below to reuse parsing errors
233 * handling */
234
235 HRESULT rc = S_OK;
236 do
237 {
238 rc = usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, data.strVendorId);
239 if (FAILED(rc)) break;
240
241 rc = usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProductId);
242 if (FAILED(rc)) break;
243
244 rc = usbFilterFieldSetter(USBFILTERIDX_DEVICE, data.strRevision);
245 if (FAILED(rc)) break;
246
247 rc = usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
248 if (FAILED(rc)) break;
249
250 rc = usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, data.strProduct);
251 if (FAILED(rc)) break;
252
253 rc = usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
254 if (FAILED(rc)) break;
255
256 rc = usbFilterFieldSetter(USBFILTERIDX_PORT, data.strPort);
257 if (FAILED(rc)) break;
258
259 rc = COMSETTER(Remote)(Bstr(data.strRemote).raw());
260 if (FAILED(rc)) break;
261
262 rc = COMSETTER(MaskedInterfaces)(data.ulMaskedInterfaces);
263 if (FAILED(rc)) break;
264 }
265 while (0);
266
267 /* Confirm successful initialization when it's the case */
268 if (SUCCEEDED(rc))
269 autoInitSpan.setSucceeded();
270
271 return rc;
272}
273
274/**
275 * Initializes the USB device filter object (short version).
276 *
277 * @param aParent Handle of the parent object.
278 */
279HRESULT USBDeviceFilter::init(USBController *aParent, IN_BSTR aName)
280{
281 LogFlowThisFunc(("aParent=%p\n", aParent));
282
283 ComAssertRet(aParent && aName && *aName, E_INVALIDARG);
284
285 /* Enclose the state transition NotReady->InInit->Ready */
286 AutoInitSpan autoInitSpan(this);
287 AssertReturn(autoInitSpan.isOk(), E_FAIL);
288
289 unconst(mParent) = aParent;
290 /* mPeer is left null */
291
292 m_fModified = false;
293
294 mData.allocate();
295
296 mData->mName = aName;
297 mData->mActive = FALSE;
298 mData->mMaskedIfs = 0;
299
300 /* initialize all filters to any match using null string */
301 USBFilterInit (&mData->mUSBFilter, USBFILTERTYPE_CAPTURE);
302 mData->mRemote = NULL;
303
304 mInList = false;
305
306 /* Confirm successful initialization */
307 autoInitSpan.setSucceeded();
308
309 return S_OK;
310}
311
312/**
313 * Initializes the object given another object
314 * (a kind of copy constructor). This object shares data with
315 * the object passed as an argument.
316 *
317 * @param aReshare
318 * When false, the original object will remain a data owner.
319 * Otherwise, data ownership will be transferred from the original
320 * object to this one.
321 *
322 * @note This object must be destroyed before the original object
323 * it shares data with is destroyed.
324 *
325 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
326 * reading if @a aReshare is false.
327 */
328HRESULT USBDeviceFilter::init (USBController *aParent, USBDeviceFilter *aThat,
329 bool aReshare /* = false */)
330{
331 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
332 aParent, aThat, aReshare));
333
334 ComAssertRet(aParent && aThat, E_INVALIDARG);
335
336 /* Enclose the state transition NotReady->InInit->Ready */
337 AutoInitSpan autoInitSpan(this);
338 AssertReturn(autoInitSpan.isOk(), E_FAIL);
339
340 unconst(mParent) = aParent;
341
342 m_fModified = false;
343
344 /* sanity */
345 AutoCaller thatCaller (aThat);
346 AssertComRCReturnRC(thatCaller.rc());
347
348 if (aReshare)
349 {
350 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
351
352 unconst(aThat->mPeer) = this;
353 mData.attach (aThat->mData);
354 }
355 else
356 {
357 unconst(mPeer) = aThat;
358
359 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
360 mData.share (aThat->mData);
361 }
362
363 /* the arbitrary ID field is not reset because
364 * the copy is a shadow of the original */
365
366 mInList = aThat->mInList;
367
368 /* Confirm successful initialization */
369 autoInitSpan.setSucceeded();
370
371 return S_OK;
372}
373
374/**
375 * Initializes the guest object given another guest object
376 * (a kind of copy constructor). This object makes a private copy of data
377 * of the original object passed as an argument.
378 *
379 * @note Locks @a aThat object for reading.
380 */
381HRESULT USBDeviceFilter::initCopy (USBController *aParent, USBDeviceFilter *aThat)
382{
383 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
384
385 ComAssertRet(aParent && aThat, E_INVALIDARG);
386
387 /* Enclose the state transition NotReady->InInit->Ready */
388 AutoInitSpan autoInitSpan(this);
389 AssertReturn(autoInitSpan.isOk(), E_FAIL);
390
391 unconst(mParent) = aParent;
392 /* mPeer is left null */
393
394 m_fModified = false;
395
396 /* sanity */
397 AutoCaller thatCaller (aThat);
398 AssertComRCReturnRC(thatCaller.rc());
399
400 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
401 mData.attachCopy (aThat->mData);
402
403 /* reset the arbitrary ID field
404 * (this field is something unique that two distinct objects, even if they
405 * are deep copies of each other, should not share) */
406 mData->mId = NULL;
407
408 mInList = aThat->mInList;
409
410 /* Confirm successful initialization */
411 autoInitSpan.setSucceeded();
412
413 return S_OK;
414}
415
416/**
417 * Uninitializes the instance and sets the ready flag to FALSE.
418 * Called either from FinalRelease() or by the parent when it gets destroyed.
419 */
420void USBDeviceFilter::uninit()
421{
422 LogFlowThisFunc(("\n"));
423
424 /* Enclose the state transition Ready->InUninit->NotReady */
425 AutoUninitSpan autoUninitSpan(this);
426 if (autoUninitSpan.uninitDone())
427 return;
428
429 mInList = false;
430
431 mData.free();
432
433 unconst(mPeer) = NULL;
434 unconst(mParent) = NULL;
435}
436
437
438// IUSBDeviceFilter properties
439////////////////////////////////////////////////////////////////////////////////
440
441STDMETHODIMP USBDeviceFilter::COMGETTER(Name) (BSTR *aName)
442{
443 CheckComArgOutPointerValid(aName);
444
445 AutoCaller autoCaller(this);
446 if (FAILED(autoCaller.rc())) return autoCaller.rc();
447
448 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
449
450 mData->mName.cloneTo(aName);
451
452 return S_OK;
453}
454
455STDMETHODIMP USBDeviceFilter::COMSETTER(Name) (IN_BSTR aName)
456{
457 CheckComArgStrNotEmptyOrNull(aName);
458
459 AutoCaller autoCaller(this);
460 if (FAILED(autoCaller.rc())) return autoCaller.rc();
461
462 /* the machine needs to be mutable */
463 AutoMutableStateDependency adep(mParent->getMachine());
464 if (FAILED(adep.rc())) return adep.rc();
465
466 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
467
468 if (mData->mName != aName)
469 {
470 m_fModified = true;
471 ComObjPtr<Machine> pMachine = mParent->getMachine();
472
473 mData.backup();
474 mData->mName = aName;
475
476 // leave the lock before informing callbacks
477 alock.release();
478
479 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
480 pMachine->setModified(Machine::IsModified_USB);
481 mlock.release();
482
483 return mParent->onDeviceFilterChange(this);
484 }
485
486 return S_OK;
487}
488
489STDMETHODIMP USBDeviceFilter::COMGETTER(Active) (BOOL *aActive)
490{
491 CheckComArgOutPointerValid(aActive);
492
493 AutoCaller autoCaller(this);
494 if (FAILED(autoCaller.rc())) return autoCaller.rc();
495
496 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
497
498 *aActive = mData->mActive;
499
500 return S_OK;
501}
502
503STDMETHODIMP USBDeviceFilter::COMSETTER(Active) (BOOL aActive)
504{
505 AutoCaller autoCaller(this);
506 if (FAILED(autoCaller.rc())) return autoCaller.rc();
507
508 /* the machine needs to be mutable */
509 AutoMutableStateDependency adep(mParent->getMachine());
510 if (FAILED(adep.rc())) return adep.rc();
511
512 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
513
514 if (mData->mActive != aActive)
515 {
516 m_fModified = true;
517 ComObjPtr<Machine> pMachine = mParent->getMachine();
518
519 mData.backup();
520 mData->mActive = aActive;
521
522 // leave the lock before informing callbacks
523 alock.release();
524
525 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
526 pMachine->setModified(Machine::IsModified_USB);
527 mlock.release();
528
529 return mParent->onDeviceFilterChange(this, TRUE /* aActiveChanged */);
530 }
531
532 return S_OK;
533}
534
535STDMETHODIMP USBDeviceFilter::COMGETTER(VendorId) (BSTR *aVendorId)
536{
537 return usbFilterFieldGetter(USBFILTERIDX_VENDOR_ID, aVendorId);
538}
539
540STDMETHODIMP USBDeviceFilter::COMSETTER(VendorId) (IN_BSTR aVendorId)
541{
542 return usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, aVendorId);
543}
544
545STDMETHODIMP USBDeviceFilter::COMGETTER(ProductId) (BSTR *aProductId)
546{
547 return usbFilterFieldGetter(USBFILTERIDX_PRODUCT_ID, aProductId);
548}
549
550STDMETHODIMP USBDeviceFilter::COMSETTER(ProductId) (IN_BSTR aProductId)
551{
552 return usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, aProductId);
553 }
554
555STDMETHODIMP USBDeviceFilter::COMGETTER(Revision) (BSTR *aRevision)
556{
557 return usbFilterFieldGetter(USBFILTERIDX_DEVICE, aRevision);
558}
559
560STDMETHODIMP USBDeviceFilter::COMSETTER(Revision) (IN_BSTR aRevision)
561{
562 return usbFilterFieldSetter(USBFILTERIDX_DEVICE, aRevision);
563}
564
565STDMETHODIMP USBDeviceFilter::COMGETTER(Manufacturer) (BSTR *aManufacturer)
566{
567 return usbFilterFieldGetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
568}
569
570STDMETHODIMP USBDeviceFilter::COMSETTER(Manufacturer) (IN_BSTR aManufacturer)
571{
572 return usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
573}
574
575STDMETHODIMP USBDeviceFilter::COMGETTER(Product) (BSTR *aProduct)
576{
577 return usbFilterFieldGetter(USBFILTERIDX_PRODUCT_STR, aProduct);
578}
579
580STDMETHODIMP USBDeviceFilter::COMSETTER(Product) (IN_BSTR aProduct)
581{
582 return usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, aProduct);
583}
584
585STDMETHODIMP USBDeviceFilter::COMGETTER(SerialNumber) (BSTR *aSerialNumber)
586{
587 return usbFilterFieldGetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
588}
589
590STDMETHODIMP USBDeviceFilter::COMSETTER(SerialNumber) (IN_BSTR aSerialNumber)
591{
592 return usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
593}
594
595STDMETHODIMP USBDeviceFilter::COMGETTER(Port) (BSTR *aPort)
596{
597 return usbFilterFieldGetter(USBFILTERIDX_PORT, aPort);
598}
599
600STDMETHODIMP USBDeviceFilter::COMSETTER(Port) (IN_BSTR aPort)
601{
602 return usbFilterFieldSetter(USBFILTERIDX_PORT, aPort);
603}
604
605STDMETHODIMP USBDeviceFilter::COMGETTER(Remote) (BSTR *aRemote)
606{
607 CheckComArgOutPointerValid(aRemote);
608
609 AutoCaller autoCaller(this);
610 if (FAILED(autoCaller.rc())) return autoCaller.rc();
611
612 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
613
614 mData->mRemote.string().cloneTo(aRemote);
615
616 return S_OK;
617}
618
619STDMETHODIMP USBDeviceFilter::COMSETTER(Remote) (IN_BSTR aRemote)
620{
621 AutoCaller autoCaller(this);
622 if (FAILED(autoCaller.rc())) return autoCaller.rc();
623
624 /* the machine needs to be mutable */
625 AutoMutableStateDependency adep(mParent->getMachine());
626 if (FAILED(adep.rc())) return adep.rc();
627
628 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
629
630 if (mData->mRemote.string() != aRemote)
631 {
632 Data::BOOLFilter flt = aRemote;
633 ComAssertRet(!flt.isNull(), E_FAIL);
634 if (!flt.isValid())
635 return setError(E_INVALIDARG,
636 tr("Remote state filter string '%ls' is not valid (error at position %d)"),
637 aRemote, flt.errorPosition() + 1);
638
639 m_fModified = true;
640 ComObjPtr<Machine> pMachine = mParent->getMachine();
641
642 mData.backup();
643 mData->mRemote = flt;
644
645 // leave the lock before informing callbacks
646 alock.release();
647
648 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
649 pMachine->setModified(Machine::IsModified_USB);
650 mlock.release();
651
652 return mParent->onDeviceFilterChange(this);
653 }
654
655 return S_OK;
656}
657
658STDMETHODIMP USBDeviceFilter::COMGETTER(MaskedInterfaces) (ULONG *aMaskedIfs)
659{
660 CheckComArgOutPointerValid(aMaskedIfs);
661
662 AutoCaller autoCaller(this);
663 if (FAILED(autoCaller.rc())) return autoCaller.rc();
664
665 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
666
667 *aMaskedIfs = mData->mMaskedIfs;
668
669 return S_OK;
670}
671
672STDMETHODIMP USBDeviceFilter::COMSETTER(MaskedInterfaces) (ULONG aMaskedIfs)
673{
674 AutoCaller autoCaller(this);
675 if (FAILED(autoCaller.rc())) return autoCaller.rc();
676
677 /* the machine needs to be mutable */
678 AutoMutableStateDependency adep(mParent->getMachine());
679 if (FAILED(adep.rc())) return adep.rc();
680
681 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
682
683 if (mData->mMaskedIfs != aMaskedIfs)
684 {
685 m_fModified = true;
686 ComObjPtr<Machine> pMachine = mParent->getMachine();
687
688 mData.backup();
689 mData->mMaskedIfs = aMaskedIfs;
690
691 // leave the lock before informing callbacks
692 alock.release();
693
694 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
695 pMachine->setModified(Machine::IsModified_USB);
696 mlock.release();
697
698 return mParent->onDeviceFilterChange(this);
699 }
700
701 return S_OK;
702}
703
704// public methods only for internal purposes
705////////////////////////////////////////////////////////////////////////////////
706
707bool USBDeviceFilter::isModified()
708{
709 AutoCaller autoCaller(this);
710 AssertComRCReturn (autoCaller.rc(), false);
711
712 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
713 return m_fModified;
714}
715
716/**
717 * @note Locks this object for writing.
718 */
719void USBDeviceFilter::rollback()
720{
721 /* sanity */
722 AutoCaller autoCaller(this);
723 AssertComRCReturnVoid(autoCaller.rc());
724
725 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
726
727 mData.rollback();
728}
729
730/**
731 * @note Locks this object for writing, together with the peer object (also
732 * for writing) if there is one.
733 */
734void USBDeviceFilter::commit()
735{
736 /* sanity */
737 AutoCaller autoCaller(this);
738 AssertComRCReturnVoid (autoCaller.rc());
739
740 /* sanity too */
741 AutoCaller peerCaller (mPeer);
742 AssertComRCReturnVoid (peerCaller.rc());
743
744 /* lock both for writing since we modify both (mPeer is "master" so locked
745 * first) */
746 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
747
748 if (mData.isBackedUp())
749 {
750 mData.commit();
751 if (mPeer)
752 {
753 /* attach new data to the peer and reshare it */
754 mPeer->mData.attach (mData);
755 }
756 }
757}
758
759/**
760 * Cancels sharing (if any) by making an independent copy of data.
761 * This operation also resets this object's peer to NULL.
762 *
763 * @note Locks this object for writing, together with the peer object
764 * represented by @a aThat (locked for reading).
765 */
766void USBDeviceFilter::unshare()
767{
768 /* sanity */
769 AutoCaller autoCaller(this);
770 AssertComRCReturnVoid (autoCaller.rc());
771
772 /* sanity too */
773 AutoCaller peerCaller (mPeer);
774 AssertComRCReturnVoid (peerCaller.rc());
775
776 /* peer is not modified, lock it for reading (mPeer is "master" so locked
777 * first) */
778 AutoReadLock rl(mPeer COMMA_LOCKVAL_SRC_POS);
779 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
780
781 if (mData.isShared())
782 {
783 if (!mData.isBackedUp())
784 mData.backup();
785
786 mData.commit();
787 }
788
789 unconst(mPeer) = NULL;
790}
791
792/**
793 * Generic USB filter field getter; converts the field value to UTF-16.
794 *
795 * @param aIdx The field index.
796 * @param aStr Where to store the value.
797 *
798 * @return COM status.
799 */
800HRESULT USBDeviceFilter::usbFilterFieldGetter(USBFILTERIDX aIdx, BSTR *aStr)
801{
802 CheckComArgOutPointerValid(aStr);
803
804 AutoCaller autoCaller(this);
805 if (FAILED(autoCaller.rc())) return autoCaller.rc();
806
807 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
808
809 Utf8Str str;
810 usbFilterFieldToString(&mData->mUSBFilter, aIdx, str);
811
812 str.cloneTo(aStr);
813
814 return S_OK;
815}
816
817/**
818 * Generic USB filter field setter, expects UTF-8 input.
819 *
820 * @param aIdx The field index.
821 * @param aStr The new value.
822 *
823 * @return COM status.
824 */
825HRESULT USBDeviceFilter::usbFilterFieldSetter(USBFILTERIDX aIdx,
826 const Utf8Str &strNew)
827{
828 AutoCaller autoCaller(this);
829 if (FAILED(autoCaller.rc())) return autoCaller.rc();
830
831 /* the machine needs to be mutable */
832 AutoMutableStateDependency adep(mParent->getMachine());
833 if (FAILED(adep.rc())) return adep.rc();
834
835 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
836
837 Utf8Str strOld;
838 usbFilterFieldToString(&mData->mUSBFilter, aIdx, strOld);
839 if (strOld != strNew)
840 {
841 m_fModified = true;
842 ComObjPtr<Machine> pMachine = mParent->getMachine();
843
844 mData.backup();
845
846 Utf8Str errStr;
847 HRESULT rc = usbFilterFieldFromString(&mData->mUSBFilter, aIdx, strNew, errStr);
848 if (FAILED(rc))
849 {
850 mData.rollback();
851 return setError(rc, "%s", errStr.c_str());
852 }
853
854 // leave the lock before informing callbacks
855 alock.release();
856
857 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
858 pMachine->setModified(Machine::IsModified_USB);
859 mlock.release();
860
861 return mParent->onDeviceFilterChange(this);
862 }
863
864 return S_OK;
865}
866
867/**
868 * Generic USB filter field setter, expects UTF-16 input.
869 *
870 * @param aIdx The field index.
871 * @param aStr The new value.
872 *
873 * @return COM status.
874 */
875HRESULT USBDeviceFilter::usbFilterFieldSetter(USBFILTERIDX aIdx,
876 IN_BSTR aStr)
877{
878 return usbFilterFieldSetter(aIdx, Utf8Str(aStr));
879}
880
881
882////////////////////////////////////////////////////////////////////////////////
883// HostUSBDeviceFilter
884////////////////////////////////////////////////////////////////////////////////
885
886// constructor / destructor
887////////////////////////////////////////////////////////////////////////////////
888
889HostUSBDeviceFilter::HostUSBDeviceFilter()
890 : mParent(NULL)
891{
892}
893
894HostUSBDeviceFilter::~HostUSBDeviceFilter()
895{
896}
897
898
899HRESULT HostUSBDeviceFilter::FinalConstruct()
900{
901 return S_OK;
902}
903
904void HostUSBDeviceFilter::FinalRelease()
905{
906 uninit();
907}
908
909// public initializer/uninitializer for internal purposes only
910////////////////////////////////////////////////////////////////////////////////
911
912/**
913 * Initializes the USB device filter object.
914 *
915 * @param aParent Handle of the parent object.
916 */
917HRESULT HostUSBDeviceFilter::init(Host *aParent,
918 const settings::USBDeviceFilter &data)
919{
920 LogFlowThisFunc(("aParent=%p\n", aParent));
921
922 ComAssertRet(aParent && !data.strName.isEmpty(), E_INVALIDARG);
923
924 /* Enclose the state transition NotReady->InInit->Ready */
925 AutoInitSpan autoInitSpan(this);
926 AssertReturn(autoInitSpan.isOk(), E_FAIL);
927
928 unconst(mParent) = aParent;
929
930 /* register with parent early, since uninit() will unconditionally
931 * unregister on failure */
932 mParent->addChild(this);
933
934 mData.allocate();
935 mData->mName = data.strName;
936 mData->mActive = data.fActive;
937 USBFilterInit (&mData->mUSBFilter, USBFILTERTYPE_IGNORE);
938 mData->mRemote = NULL;
939 mData->mMaskedIfs = 0;
940
941 mInList = false;
942
943 /* use setters for the attributes below to reuse parsing errors
944 * handling */
945
946 HRESULT rc = S_OK;
947 do
948 {
949 rc = COMSETTER(Action)(data.action);
950 if (FAILED(rc)) break;
951
952 rc = usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, data.strVendorId);
953 if (FAILED(rc)) break;
954
955 rc = usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProductId);
956 if (FAILED(rc)) break;
957
958 rc = usbFilterFieldSetter(USBFILTERIDX_DEVICE, data.strRevision);
959 if (FAILED(rc)) break;
960
961 rc = usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
962 if (FAILED(rc)) break;
963
964 rc = usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProduct);
965 if (FAILED(rc)) break;
966
967 rc = usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
968 if (FAILED(rc)) break;
969
970 rc = usbFilterFieldSetter(USBFILTERIDX_PORT, data.strPort);
971 if (FAILED(rc)) break;
972 }
973 while (0);
974
975 /* Confirm successful initialization when it's the case */
976 if (SUCCEEDED(rc))
977 autoInitSpan.setSucceeded();
978
979 return rc;
980}
981
982/**
983 * Initializes the USB device filter object (short version).
984 *
985 * @param aParent Handle of the parent object.
986 */
987HRESULT HostUSBDeviceFilter::init (Host *aParent, IN_BSTR aName)
988{
989 LogFlowThisFunc(("aParent=%p\n", aParent));
990
991 ComAssertRet(aParent && aName && *aName, E_INVALIDARG);
992
993 /* Enclose the state transition NotReady->InInit->Ready */
994 AutoInitSpan autoInitSpan(this);
995 AssertReturn(autoInitSpan.isOk(), E_FAIL);
996
997 unconst(mParent) = aParent;
998
999 /* register with parent early, since uninit() will unconditionally
1000 * unregister on failure */
1001 mParent->addChild(this);
1002
1003 mData.allocate();
1004
1005 mData->mName = aName;
1006 mData->mActive = FALSE;
1007 mInList = false;
1008 USBFilterInit (&mData->mUSBFilter, USBFILTERTYPE_IGNORE);
1009 mData->mRemote = NULL;
1010 mData->mMaskedIfs = 0;
1011
1012 /* Confirm successful initialization */
1013 autoInitSpan.setSucceeded();
1014
1015 return S_OK;
1016}
1017
1018/**
1019 * Uninitializes the instance and sets the ready flag to FALSE.
1020 * Called either from FinalRelease() or by the parent when it gets destroyed.
1021 */
1022void HostUSBDeviceFilter::uninit()
1023{
1024 LogFlowThisFunc(("\n"));
1025
1026 /* Enclose the state transition Ready->InUninit->NotReady */
1027 AutoUninitSpan autoUninitSpan(this);
1028 if (autoUninitSpan.uninitDone())
1029 return;
1030
1031 mInList = false;
1032
1033 mData.free();
1034
1035 mParent->removeChild(this);
1036
1037 unconst(mParent) = NULL;
1038}
1039
1040/**
1041 * Most of the USB bits are protect by one lock to simplify things.
1042 * This lock is currently the one of the Host object, which happens
1043 * to be our parent.
1044 */
1045RWLockHandle *HostUSBDeviceFilter::lockHandle() const
1046{
1047 return mParent->lockHandle();
1048}
1049
1050
1051// IUSBDeviceFilter properties
1052////////////////////////////////////////////////////////////////////////////////
1053
1054STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Name) (BSTR *aName)
1055{
1056 CheckComArgOutPointerValid(aName);
1057
1058 AutoCaller autoCaller(this);
1059 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1060
1061 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1062
1063 mData->mName.cloneTo(aName);
1064
1065 return S_OK;
1066}
1067
1068STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Name) (IN_BSTR aName)
1069{
1070 CheckComArgStrNotEmptyOrNull(aName);
1071
1072 AutoCaller autoCaller(this);
1073 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1074
1075 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1076
1077 if (mData->mName != aName)
1078 {
1079 mData->mName = aName;
1080
1081 /* leave the lock before informing callbacks */
1082 alock.release();
1083
1084 return mParent->onUSBDeviceFilterChange (this);
1085 }
1086
1087 return S_OK;
1088}
1089
1090STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Active) (BOOL *aActive)
1091{
1092 CheckComArgOutPointerValid(aActive);
1093
1094 AutoCaller autoCaller(this);
1095 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1096
1097 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1098
1099 *aActive = mData->mActive;
1100
1101 return S_OK;
1102}
1103
1104STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Active) (BOOL aActive)
1105{
1106 AutoCaller autoCaller(this);
1107 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1108
1109 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1110
1111 if (mData->mActive != aActive)
1112 {
1113 mData->mActive = aActive;
1114
1115 /* leave the lock before informing callbacks */
1116 alock.release();
1117
1118 return mParent->onUSBDeviceFilterChange (this, TRUE /* aActiveChanged */);
1119 }
1120
1121 return S_OK;
1122}
1123
1124STDMETHODIMP HostUSBDeviceFilter::COMGETTER(VendorId) (BSTR *aVendorId)
1125{
1126 return usbFilterFieldGetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1127}
1128
1129STDMETHODIMP HostUSBDeviceFilter::COMSETTER(VendorId) (IN_BSTR aVendorId)
1130{
1131 return usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1132}
1133
1134STDMETHODIMP HostUSBDeviceFilter::COMGETTER(ProductId) (BSTR *aProductId)
1135{
1136 return usbFilterFieldGetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1137}
1138
1139STDMETHODIMP HostUSBDeviceFilter::COMSETTER(ProductId) (IN_BSTR aProductId)
1140{
1141 return usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1142}
1143
1144STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Revision) (BSTR *aRevision)
1145{
1146 return usbFilterFieldGetter(USBFILTERIDX_DEVICE, aRevision);
1147}
1148
1149STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Revision) (IN_BSTR aRevision)
1150{
1151 return usbFilterFieldSetter(USBFILTERIDX_DEVICE, aRevision);
1152}
1153
1154STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Manufacturer) (BSTR *aManufacturer)
1155{
1156 return usbFilterFieldGetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1157}
1158
1159STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Manufacturer) (IN_BSTR aManufacturer)
1160{
1161 return usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1162}
1163
1164STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Product) (BSTR *aProduct)
1165{
1166 return usbFilterFieldGetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1167}
1168
1169STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Product) (IN_BSTR aProduct)
1170{
1171 return usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1172}
1173
1174STDMETHODIMP HostUSBDeviceFilter::COMGETTER(SerialNumber) (BSTR *aSerialNumber)
1175{
1176 return usbFilterFieldGetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1177}
1178
1179STDMETHODIMP HostUSBDeviceFilter::COMSETTER(SerialNumber) (IN_BSTR aSerialNumber)
1180{
1181 return usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1182}
1183
1184STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Port) (BSTR *aPort)
1185{
1186 return usbFilterFieldGetter(USBFILTERIDX_PORT, aPort);
1187}
1188
1189STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Port) (IN_BSTR aPort)
1190{
1191 return usbFilterFieldSetter(USBFILTERIDX_PORT, aPort);
1192}
1193
1194STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Remote) (BSTR *aRemote)
1195{
1196 CheckComArgOutPointerValid(aRemote);
1197
1198 AutoCaller autoCaller(this);
1199 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1200
1201 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1202
1203 mData->mRemote.string().cloneTo(aRemote);
1204
1205 return S_OK;
1206}
1207
1208STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Remote) (IN_BSTR /* aRemote */)
1209{
1210 return setError(E_NOTIMPL,
1211 tr("The remote state filter is not supported by IHostUSBDeviceFilter objects"));
1212}
1213
1214STDMETHODIMP HostUSBDeviceFilter::COMGETTER(MaskedInterfaces) (ULONG *aMaskedIfs)
1215{
1216 CheckComArgOutPointerValid(aMaskedIfs);
1217
1218 AutoCaller autoCaller(this);
1219 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1220
1221 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1222
1223 *aMaskedIfs = mData->mMaskedIfs;
1224
1225 return S_OK;
1226}
1227
1228STDMETHODIMP HostUSBDeviceFilter::COMSETTER(MaskedInterfaces) (ULONG /* aMaskedIfs */)
1229{
1230 return setError(E_NOTIMPL,
1231 tr("The masked interfaces property is not applicable to IHostUSBDeviceFilter objects"));
1232}
1233
1234// IHostUSBDeviceFilter properties
1235////////////////////////////////////////////////////////////////////////////////
1236
1237STDMETHODIMP HostUSBDeviceFilter::COMGETTER(Action) (USBDeviceFilterAction_T *aAction)
1238{
1239 CheckComArgOutPointerValid(aAction);
1240
1241 AutoCaller autoCaller(this);
1242 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1243
1244 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1245
1246 switch (USBFilterGetFilterType (&mData->mUSBFilter))
1247 {
1248 case USBFILTERTYPE_IGNORE: *aAction = USBDeviceFilterAction_Ignore; break;
1249 case USBFILTERTYPE_CAPTURE: *aAction = USBDeviceFilterAction_Hold; break;
1250 default: *aAction = USBDeviceFilterAction_Null; break;
1251 }
1252
1253 return S_OK;
1254}
1255
1256STDMETHODIMP HostUSBDeviceFilter::COMSETTER(Action) (USBDeviceFilterAction_T aAction)
1257{
1258 AutoCaller autoCaller(this);
1259 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1260
1261 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1262
1263 USBFILTERTYPE filterType;
1264 switch (aAction)
1265 {
1266 case USBDeviceFilterAction_Ignore: filterType = USBFILTERTYPE_IGNORE; break;
1267 case USBDeviceFilterAction_Hold: filterType = USBFILTERTYPE_CAPTURE; break;
1268 case USBDeviceFilterAction_Null:
1269 return setError(E_INVALIDARG,
1270 tr("Action value InvalidUSBDeviceFilterAction is not permitted"));
1271 default:
1272 return setError(E_INVALIDARG,
1273 tr("Invalid action %d"),
1274 aAction);
1275 }
1276 if (USBFilterGetFilterType (&mData->mUSBFilter) != filterType)
1277 {
1278 int vrc = USBFilterSetFilterType (&mData->mUSBFilter, filterType);
1279 if (RT_FAILURE(vrc))
1280 return setError(E_INVALIDARG,
1281 tr("Unexpected error %Rrc"),
1282 vrc);
1283
1284 /* leave the lock before informing callbacks */
1285 alock.release();
1286
1287 return mParent->onUSBDeviceFilterChange (this);
1288 }
1289
1290 return S_OK;
1291}
1292
1293/**
1294 * Generic USB filter field getter.
1295 *
1296 * @param aIdx The field index.
1297 * @param aStr Where to store the value.
1298 *
1299 * @return COM status.
1300 */
1301HRESULT HostUSBDeviceFilter::usbFilterFieldGetter(USBFILTERIDX aIdx, BSTR *aStr)
1302{
1303 CheckComArgOutPointerValid(aStr);
1304
1305 AutoCaller autoCaller(this);
1306 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1307
1308 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1309
1310 Utf8Str str;
1311 usbFilterFieldToString(&mData->mUSBFilter, aIdx, str);
1312
1313 str.cloneTo(aStr);
1314
1315 return S_OK;
1316}
1317
1318void HostUSBDeviceFilter::saveSettings(settings::USBDeviceFilter &data)
1319{
1320 AutoCaller autoCaller(this);
1321 AssertComRCReturnVoid(autoCaller.rc());
1322
1323 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1324
1325 data.strName = mData->mName;
1326 data.fActive = !!mData->mActive;
1327
1328 usbFilterFieldToString(&mData->mUSBFilter, USBFILTERIDX_VENDOR_ID, data.strVendorId);
1329 usbFilterFieldToString(&mData->mUSBFilter, USBFILTERIDX_PRODUCT_ID, data.strProductId);
1330 usbFilterFieldToString(&mData->mUSBFilter, USBFILTERIDX_DEVICE, data.strRevision);
1331 usbFilterFieldToString(&mData->mUSBFilter, USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
1332 usbFilterFieldToString(&mData->mUSBFilter, USBFILTERIDX_PRODUCT_STR, data.strProduct);
1333 usbFilterFieldToString(&mData->mUSBFilter, USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
1334 usbFilterFieldToString(&mData->mUSBFilter, USBFILTERIDX_PORT, data.strPort);
1335
1336 COMGETTER(Action)(&data.action);
1337}
1338
1339
1340/**
1341 * Generic USB filter field setter.
1342 *
1343 * @param aIdx The field index.
1344 * @param aStr The new value.
1345 * @param aName The translated field name (for error messages).
1346 *
1347 * @return COM status.
1348 */
1349HRESULT HostUSBDeviceFilter::usbFilterFieldSetter(USBFILTERIDX aIdx, Bstr aStr)
1350{
1351 AutoCaller autoCaller(this);
1352 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1353
1354 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1355
1356 Utf8Str strOld;
1357 Utf8Str strNew(aStr);
1358 usbFilterFieldToString(&mData->mUSBFilter, aIdx, strOld);
1359 if (strOld != strNew)
1360 {
1361 //mData.backup();
1362
1363 Utf8Str errStr;
1364 HRESULT rc = USBDeviceFilter::usbFilterFieldFromString(&mData->mUSBFilter, aIdx, aStr, errStr);
1365 if (FAILED(rc))
1366 {
1367 //mData.rollback();
1368 return setError(rc, "%s", errStr.c_str());
1369 }
1370
1371 /* leave the lock before informing callbacks */
1372 alock.release();
1373
1374 return mParent->onUSBDeviceFilterChange(this);
1375 }
1376
1377 return S_OK;
1378}
1379/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use