| 106 | | /** Pointer to our configuration values node. */ |
|---|
| 107 | | PCFGMNODE mpValueNode; |
|---|
| 108 | | /** Pointer to our configuration timestamps node. */ |
|---|
| 109 | | PCFGMNODE mpTimestampNode; |
|---|
| 110 | | /** Pointer to our configuration flags node. */ |
|---|
| 111 | | PCFGMNODE mpFlagsNode; |
|---|
| | 126 | /** Structure for holding a property */ |
|---|
| | 127 | struct Property |
|---|
| | 128 | { |
|---|
| | 129 | /** The name of the property */ |
|---|
| | 130 | std::string mName; |
|---|
| | 131 | /** The property value */ |
|---|
| | 132 | std::string mValue; |
|---|
| | 133 | /** The timestamp of the property */ |
|---|
| | 134 | uint64_t mTimestamp; |
|---|
| | 135 | /** The property flags */ |
|---|
| | 136 | uint32_t mFlags; |
|---|
| | 137 | /** Constructor with const char * */ |
|---|
| | 138 | Property(const char *pcszName, const char *pcszValue, |
|---|
| | 139 | uint64_t u64Timestamp, uint32_t u32Flags) |
|---|
| | 140 | : mName(pcszName), mValue(pcszValue), mTimestamp(u64Timestamp), |
|---|
| | 141 | mFlags(u32Flags) {} |
|---|
| | 142 | /** Constructor with std::string */ |
|---|
| | 143 | Property(std::string name, std::string value, uint64_t u64Timestamp, |
|---|
| | 144 | uint32_t u32Flags) |
|---|
| | 145 | : mName(name), mValue(value), mTimestamp(u64Timestamp), |
|---|
| | 146 | mFlags(u32Flags) {} |
|---|
| | 147 | }; |
|---|
| | 148 | /** The properties list type */ |
|---|
| | 149 | typedef std::list <Property> PropertyList; |
|---|
| | 150 | /** The property list */ |
|---|
| | 151 | PropertyList mProperties; |
|---|
| | 350 | /** |
|---|
| | 351 | * Set a block of properties in the property registry, checking the validity |
|---|
| | 352 | * of the arguments passed. |
|---|
| | 353 | * |
|---|
| | 354 | * @returns iprt status value |
|---|
| | 355 | * @param cParms the number of HGCM parameters supplied |
|---|
| | 356 | * @param paParms the array of HGCM parameters |
|---|
| | 357 | * @thread HGCM |
|---|
| | 358 | */ |
|---|
| | 359 | int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) |
|---|
| | 360 | { |
|---|
| | 361 | char **ppNames, **ppValues, **ppFlags; |
|---|
| | 362 | uint64_t *pTimestamps; |
|---|
| | 363 | uint32_t cbDummy; |
|---|
| | 364 | int rc = VINF_SUCCESS; |
|---|
| | 365 | |
|---|
| | 366 | /* |
|---|
| | 367 | * Get and validate the parameters |
|---|
| | 368 | */ |
|---|
| | 369 | if ( (cParms != 4) |
|---|
| | 370 | || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[0], (void **) &ppNames, &cbDummy)) |
|---|
| | 371 | || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[1], (void **) &ppValues, &cbDummy)) |
|---|
| | 372 | || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[2], (void **) &pTimestamps, &cbDummy)) |
|---|
| | 373 | || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[3], (void **) &ppFlags, &cbDummy)) |
|---|
| | 374 | ) |
|---|
| | 375 | rc = VERR_INVALID_PARAMETER; |
|---|
| | 376 | |
|---|
| | 377 | /* |
|---|
| | 378 | * Add the properties to the end of the list. If we succeed then we |
|---|
| | 379 | * will remove duplicates afterwards. |
|---|
| | 380 | */ |
|---|
| | 381 | /* Remember the last property before we started adding, for rollback or |
|---|
| | 382 | * cleanup. */ |
|---|
| | 383 | PropertyList::iterator itEnd = mProperties.end(); |
|---|
| | 384 | if (!mProperties.empty()) |
|---|
| | 385 | --itEnd; |
|---|
| | 386 | try |
|---|
| | 387 | { |
|---|
| | 388 | for (unsigned i = 0; RT_SUCCESS(rc) && ppNames[i] != NULL; ++i) |
|---|
| | 389 | { |
|---|
| | 390 | uint32_t fFlags; |
|---|
| | 391 | if ( !VALID_PTR(ppNames[i]) |
|---|
| | 392 | || !VALID_PTR(ppValues[i]) |
|---|
| | 393 | || !VALID_PTR(ppFlags[i]) |
|---|
| | 394 | ) |
|---|
| | 395 | rc = VERR_INVALID_POINTER; |
|---|
| | 396 | if (RT_SUCCESS(rc)) |
|---|
| | 397 | rc = validateFlags(ppFlags[i], &fFlags); |
|---|
| | 398 | if (RT_SUCCESS(rc)) |
|---|
| | 399 | mProperties.push_back(Property(ppNames[i], ppValues[i], |
|---|
| | 400 | pTimestamps[i], fFlags)); |
|---|
| | 401 | } |
|---|
| | 402 | } |
|---|
| | 403 | catch (std::bad_alloc) |
|---|
| | 404 | { |
|---|
| | 405 | rc = VERR_NO_MEMORY; |
|---|
| | 406 | } |
|---|
| | 407 | |
|---|
| | 408 | /* |
|---|
| | 409 | * If all went well then remove the duplicate elements. |
|---|
| | 410 | */ |
|---|
| | 411 | if (RT_SUCCESS(rc) && itEnd != mProperties.end()) |
|---|
| | 412 | { |
|---|
| | 413 | ++itEnd; |
|---|
| | 414 | for (unsigned i = 0; ppNames[i] != NULL; ++i) |
|---|
| | 415 | { |
|---|
| | 416 | bool found = false; |
|---|
| | 417 | for (PropertyList::iterator it = mProperties.begin(); |
|---|
| | 418 | !found && it != itEnd; ++it) |
|---|
| | 419 | if (it->mName.compare(ppNames[i]) == 0) |
|---|
| | 420 | { |
|---|
| | 421 | found = true; |
|---|
| | 422 | mProperties.erase(it); |
|---|
| | 423 | } |
|---|
| | 424 | } |
|---|
| | 425 | } |
|---|
| | 426 | |
|---|
| | 427 | /* |
|---|
| | 428 | * If something went wrong then rollback. This is possible because we |
|---|
| | 429 | * haven't deleted anything yet. |
|---|
| | 430 | */ |
|---|
| | 431 | if (RT_FAILURE(rc)) |
|---|
| | 432 | { |
|---|
| | 433 | if (itEnd != mProperties.end()) |
|---|
| | 434 | ++itEnd; |
|---|
| | 435 | mProperties.erase(itEnd, mProperties.end()); |
|---|
| | 436 | } |
|---|
| | 437 | return rc; |
|---|
| | 438 | } |
|---|
| 323 | | char *pszName, *pszValue; |
|---|
| 324 | | uint32_t cbName, cbValue; |
|---|
| 325 | | size_t cbValueActual; |
|---|
| 326 | | |
|---|
| 327 | | LogFlowThisFunc(("\n")); |
|---|
| 328 | | AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */ |
|---|
| 329 | | if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */ |
|---|
| 330 | | || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ |
|---|
| 331 | | || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */ |
|---|
| 332 | | ) |
|---|
| 333 | | rc = VERR_INVALID_PARAMETER; |
|---|
| 334 | | if (RT_SUCCESS(rc)) |
|---|
| 335 | | rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName); |
|---|
| 336 | | if (RT_SUCCESS(rc)) |
|---|
| 337 | | rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cbValue); |
|---|
| 338 | | if (RT_SUCCESS(rc)) |
|---|
| 339 | | rc = validateName(pszName, cbName); |
|---|
| 340 | | if (RT_SUCCESS(rc)) |
|---|
| 341 | | rc = CFGMR3QuerySize(mpValueNode, pszName, &cbValueActual); |
|---|
| 342 | | if (RT_SUCCESS(rc)) |
|---|
| 343 | | VBoxHGCMParmUInt32Set(&paParms[2], cbValueActual); |
|---|
| 344 | | if (RT_SUCCESS(rc) && (cbValueActual > cbValue)) |
|---|
| 345 | | rc = VERR_BUFFER_OVERFLOW; |
|---|
| 346 | | if (RT_SUCCESS(rc)) |
|---|
| 347 | | rc = CFGMR3QueryString(mpValueNode, pszName, pszValue, cbValue); |
|---|
| 348 | | if (RT_SUCCESS(rc)) |
|---|
| 349 | | Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", pszName, rc, cbValue, pszValue)); |
|---|
| 350 | | else if (VERR_CFGM_VALUE_NOT_FOUND == rc) |
|---|
| 351 | | rc = VERR_NOT_FOUND; |
|---|
| 352 | | LogFlowThisFunc(("rc = %Rrc\n", rc)); |
|---|
| 353 | | return rc; |
|---|
| 354 | | } |
|---|
| 355 | | |
|---|
| 356 | | |
|---|
| 357 | | /** |
|---|
| 358 | | * Retrieve a value from the property registry by name, checking the validity |
|---|
| 359 | | * of the arguments passed. If the guest has not allocated enough buffer |
|---|
| 360 | | * space for the value then we return VERR_OVERFLOW and set the size of the |
|---|
| 361 | | * buffer needed in the "size" HGCM parameter. If the name was not found at |
|---|
| 362 | | * all, we return VERR_NOT_FOUND. |
|---|
| 363 | | * |
|---|
| 364 | | * @returns iprt status value |
|---|
| 365 | | * @param cParms the number of HGCM parameters supplied |
|---|
| 366 | | * @param paParms the array of HGCM parameters |
|---|
| 367 | | * @thread HGCM |
|---|
| 368 | | */ |
|---|
| 369 | | int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) |
|---|
| 370 | | { |
|---|
| 371 | | int rc = VINF_SUCCESS; |
|---|
| 372 | | char *pszName, *pchBuf; |
|---|
| | 455 | const char *pcszName; |
|---|
| | 456 | char *pchBuf; |
|---|
| | 527 | * of the arguments passed. |
|---|
| | 528 | * |
|---|
| | 529 | * @returns iprt status value |
|---|
| | 530 | * @param cParms the number of HGCM parameters supplied |
|---|
| | 531 | * @param paParms the array of HGCM parameters |
|---|
| | 532 | * @param isGuest is this call coming from the guest (or the host)? |
|---|
| | 533 | * @throws std::bad_alloc if an out of memory condition occurs |
|---|
| | 534 | * @thread HGCM |
|---|
| | 535 | */ |
|---|
| | 536 | int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) |
|---|
| | 537 | { |
|---|
| | 538 | int rc = VINF_SUCCESS; |
|---|
| | 539 | const char *pcszName, *pcszValue, *pcszFlags = NULL; |
|---|
| | 540 | uint32_t cchName, cchValue, cchFlags = 0; |
|---|
| | 541 | uint32_t fFlags = NILFLAG; |
|---|
| | 542 | |
|---|
| | 543 | LogFlowThisFunc(("\n")); |
|---|
| | 544 | /* |
|---|
| | 545 | * First of all, make sure that we won't exceed the maximum number of properties. |
|---|
| | 546 | */ |
|---|
| | 547 | if (mProperties.size() >= MAX_PROPS) |
|---|
| | 548 | rc = VERR_TOO_MUCH_DATA; |
|---|
| | 549 | |
|---|
| | 550 | /* |
|---|
| | 551 | * General parameter correctness checking. |
|---|
| | 552 | */ |
|---|
| | 553 | if ( RT_SUCCESS(rc) |
|---|
| | 554 | && ( (cParms < 2) || (cParms > 3) /* Hardcoded value as the next lines depend on it. */ |
|---|
| | 555 | || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], |
|---|
| | 556 | (const void **) &pcszName, &cchName)) /* name */ |
|---|
| | 557 | || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[1], |
|---|
| | 558 | (const void **) &pcszValue, &cchValue)) /* value */ |
|---|
| | 559 | || ( (3 == cParms) |
|---|
| | 560 | && RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[2], |
|---|
| | 561 | (const void **) &pcszFlags, &cchFlags)) /* flags */ |
|---|
| | 562 | ) |
|---|
| | 563 | ) |
|---|
| | 564 | ) |
|---|
| | 565 | rc = VERR_INVALID_PARAMETER; |
|---|
| | 566 | |
|---|
| | 567 | /* |
|---|
| | 568 | * Check the values passed in the parameters for correctness. |
|---|
| | 569 | */ |
|---|
| | 570 | if (RT_SUCCESS(rc)) |
|---|
| | 571 | rc = validateName(pcszName, cchName); |
|---|
| | 572 | if (RT_SUCCESS(rc)) |
|---|
| | 573 | rc = validateValue(pcszValue, cchValue); |
|---|
| | 574 | if ((3 == cParms) && RT_SUCCESS(rc)) |
|---|
| | 575 | rc = RTStrValidateEncodingEx(pcszFlags, cchFlags, |
|---|
| | 576 | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); |
|---|
| | 577 | if ((3 == cParms) && RT_SUCCESS(rc)) |
|---|
| | 578 | rc = validateFlags(pcszFlags, &fFlags); |
|---|
| | 579 | |
|---|
| | 580 | /* |
|---|
| | 581 | * If the property already exists, check its flags to see if we are allowed |
|---|
| | 582 | * to change it. |
|---|
| | 583 | */ |
|---|
| | 584 | PropertyList::iterator it; |
|---|
| | 585 | bool found = false; |
|---|
| | 586 | if (RT_SUCCESS(rc)) |
|---|
| | 587 | for (it = mProperties.begin(); it != mProperties.end(); ++it) |
|---|
| | 588 | if (it->mName.compare(pcszName) == 0) |
|---|
| | 589 | { |
|---|
| | 590 | found = true; |
|---|
| | 591 | break; |
|---|
| | 592 | } |
|---|
| | 593 | if (RT_SUCCESS(rc) && found) |
|---|
| | 594 | if ( (isGuest && (it->mFlags & RDONLYGUEST)) |
|---|
| | 595 | || (!isGuest && (it->mFlags & RDONLYHOST)) |
|---|
| | 596 | ) |
|---|
| | 597 | rc = VERR_PERMISSION_DENIED; |
|---|
| | 598 | |
|---|
| | 599 | /* |
|---|
| | 600 | * Set the actual value |
|---|
| | 601 | */ |
|---|
| | 602 | if (RT_SUCCESS(rc)) |
|---|
| | 603 | { |
|---|
| | 604 | RTTIMESPEC time; |
|---|
| | 605 | uint64_t u64TimeNano = RTTimeSpecGetNano(RTTimeNow(&time)); |
|---|
| | 606 | if (found) |
|---|
| | 607 | { |
|---|
| | 608 | it->mValue = pcszValue; |
|---|
| | 609 | it->mTimestamp = u64TimeNano; |
|---|
| | 610 | it->mFlags = fFlags; |
|---|
| | 611 | } |
|---|
| | 612 | else /* This can throw. No problem as we have nothing to roll back. */ |
|---|
| | 613 | mProperties.push_back(Property(pcszName, pcszValue, u64TimeNano, fFlags)); |
|---|
| | 614 | } |
|---|
| | 615 | |
|---|
| | 616 | /* |
|---|
| | 617 | * Send a notification to the host and return. |
|---|
| | 618 | */ |
|---|
| | 619 | if (RT_SUCCESS(rc)) |
|---|
| | 620 | { |
|---|
| | 621 | // if (isGuest) /* Notify the host even for properties that the host |
|---|
| | 622 | // * changed. Less efficient, but ensures consistency. */ |
|---|
| | 623 | notifyHost(pcszName); |
|---|
| | 624 | Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue)); |
|---|
| | 625 | } |
|---|
| | 626 | LogFlowThisFunc(("rc = %Rrc\n", rc)); |
|---|
| | 627 | return rc; |
|---|
| | 628 | } |
|---|
| | 629 | |
|---|
| | 630 | |
|---|
| | 631 | /** |
|---|
| | 632 | * Remove a value in the property registry by name, checking the validity |
|---|
| | 633 | * of the arguments passed. |
|---|
| | 634 | * |
|---|
| | 635 | * @returns iprt status value |
|---|
| | 636 | * @param cParms the number of HGCM parameters supplied |
|---|
| | 637 | * @param paParms the array of HGCM parameters |
|---|
| | 638 | * @param isGuest is this call coming from the guest (or the host)? |
|---|
| | 639 | * @thread HGCM |
|---|
| | 640 | */ |
|---|
| | 641 | int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) |
|---|
| | 642 | { |
|---|
| | 643 | int rc = VINF_SUCCESS; |
|---|
| | 644 | const char *pcszName; |
|---|
| | 645 | uint32_t cbName; |
|---|
| | 646 | |
|---|
| | 647 | LogFlowThisFunc(("\n")); |
|---|
| | 648 | |
|---|
| | 649 | /* |
|---|
| | 650 | * Check the user-supplied parameters. |
|---|
| | 651 | */ |
|---|
| | 652 | if ( (cParms != 1) /* Hardcoded value as the next lines depend on it. */ |
|---|
| | 653 | || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0], |
|---|
| | 654 | (const void **) &pcszName, &cbName)) /* name */ |
|---|
| | 655 | ) |
|---|
| | 656 | rc = VERR_INVALID_PARAMETER; |
|---|
| | 657 | if (RT_SUCCESS(rc)) |
|---|
| | 658 | rc = validateName(pcszName, cbName); |
|---|
| | 659 | |
|---|
| | 660 | /* |
|---|
| | 661 | * If the property exists, check its flags to see if we are allowed |
|---|
| | 662 | * to change it. |
|---|
| | 663 | */ |
|---|
| | 664 | PropertyList::iterator it; |
|---|
| | 665 | bool found = false; |
|---|
| | 666 | if (RT_SUCCESS(rc)) |
|---|
| | 667 | for (it = mProperties.begin(); it != mProperties.end(); ++it) |
|---|
| | 668 | if (it->mName.compare(pcszName) == 0) |
|---|
| | 669 | { |
|---|
| | 670 | found = true; |
|---|
| | 671 | break; |
|---|
| | 672 | } |
|---|
| | 673 | if (RT_SUCCESS(rc) && found) |
|---|
| | 674 | if ( (isGuest && (it->mFlags & RDONLYGUEST)) |
|---|
| | 675 | || (!isGuest && (it->mFlags & RDONLYHOST)) |
|---|
| | 676 | ) |
|---|
| | 677 | rc = VERR_PERMISSION_DENIED; |
|---|
| | 678 | |
|---|
| | 679 | /* |
|---|
| | 680 | * And delete the property if all is well. |
|---|
| | 681 | */ |
|---|
| | 682 | if (RT_SUCCESS(rc) && found) |
|---|
| | 683 | { |
|---|
| | 684 | mProperties.erase(it); |
|---|
| | 685 | // if (isGuest) /* Notify the host even for properties that the host |
|---|
| | 686 | // * changed. Less efficient, but ensures consistency. */ |
|---|
| | 687 | notifyHost(pcszName); |
|---|
| | 688 | } |
|---|
| | 689 | LogFlowThisFunc(("rc = %Rrc\n", rc)); |
|---|
| | 690 | return rc; |
|---|
| | 691 | } |
|---|
| | 692 | |
|---|
| | 693 | /** |
|---|
| | 694 | * Enumerate guest properties by mask, checking the validity |
|---|
| 482 | | /* |
|---|
| 483 | | * Check the values passed in the parameters for correctness. |
|---|
| 484 | | */ |
|---|
| 485 | | if (RT_SUCCESS(rc)) |
|---|
| 486 | | rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName); |
|---|
| 487 | | if (RT_SUCCESS(rc)) |
|---|
| 488 | | rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue); |
|---|
| 489 | | if (RT_SUCCESS(rc)) |
|---|
| 490 | | rc = validateName(pszName, cchName); |
|---|
| 491 | | if (RT_SUCCESS(rc)) |
|---|
| 492 | | rc = validateValue(pszValue, cchValue); |
|---|
| 493 | | |
|---|
| 494 | | /* |
|---|
| 495 | | * If the property already exists, check its flags to see if we are allowed |
|---|
| 496 | | * to change it. |
|---|
| 497 | | */ |
|---|
| 498 | | if (RT_SUCCESS(rc)) |
|---|
| 499 | | { |
|---|
| 500 | | CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); /* Failure is no problem here. */ |
|---|
| 501 | | if ( (isGuest && (fFlags & RDONLYGUEST)) |
|---|
| 502 | | || (!isGuest && (fFlags & RDONLYHOST)) |
|---|
| 503 | | ) |
|---|
| 504 | | rc = VERR_PERMISSION_DENIED; |
|---|
| 505 | | } |
|---|
| 506 | | |
|---|
| 507 | | /* |
|---|
| 508 | | * Check whether the user supplied flags (if any) are valid. |
|---|
| 509 | | */ |
|---|
| 510 | | if (RT_SUCCESS(rc) && (3 == cParms)) |
|---|
| 511 | | { |
|---|
| 512 | | char *pszFlags; |
|---|
| 513 | | uint32_t cchFlags; |
|---|
| 514 | | rc = VBoxHGCMParmPtrGet(&paParms[2], (void **) &pszFlags, &cchFlags); |
|---|
| 515 | | if (RT_SUCCESS(rc)) |
|---|
| 516 | | rc = validateFlags(pszFlags, &fFlags); |
|---|
| 517 | | } |
|---|
| 518 | | /* |
|---|
| 519 | | * Set the actual value |
|---|
| 520 | | */ |
|---|
| 521 | | if (RT_SUCCESS(rc)) |
|---|
| 522 | | { |
|---|
| 523 | | RTTIMESPEC time; |
|---|
| 524 | | CFGMR3RemoveValue(mpValueNode, pszName); |
|---|
| 525 | | CFGMR3RemoveValue(mpTimestampNode, pszName); |
|---|
| 526 | | CFGMR3RemoveValue(mpFlagsNode, pszName); |
|---|
| 527 | | rc = CFGMR3InsertString(mpValueNode, pszName, pszValue); |
|---|
| 528 | | if (RT_SUCCESS(rc)) |
|---|
| 529 | | rc = CFGMR3InsertInteger(mpTimestampNode, pszName, |
|---|
| 530 | | RTTimeSpecGetNano(RTTimeNow(&time))); |
|---|
| 531 | | if (RT_SUCCESS(rc)) |
|---|
| 532 | | rc = CFGMR3InsertInteger(mpFlagsNode, pszName, fFlags); |
|---|
| 533 | | /* If anything goes wrong, make sure that we leave a clean state |
|---|
| 534 | | * behind. */ |
|---|
| 535 | | if (RT_FAILURE(rc)) |
|---|
| 536 | | { |
|---|
| 537 | | CFGMR3RemoveValue(mpValueNode, pszName); |
|---|
| 538 | | CFGMR3RemoveValue(mpTimestampNode, pszName); |
|---|
| 539 | | CFGMR3RemoveValue(mpFlagsNode, pszName); |
|---|
| 540 | | } |
|---|
| 541 | | } |
|---|
| 542 | | /* |
|---|
| 543 | | * Send a notification to the host and return. |
|---|
| 544 | | */ |
|---|
| 545 | | if (RT_SUCCESS(rc)) |
|---|
| 546 | | { |
|---|
| 547 | | if (isGuest) |
|---|
| 548 | | notifyHost(pszName); |
|---|
| 549 | | Log2(("Set string %s, rc=%Rrc, value=%s\n", pszName, rc, pszValue)); |
|---|
| 550 | | } |
|---|
| 551 | | LogFlowThisFunc(("rc = %Rrc\n", rc)); |
|---|
| 552 | | return rc; |
|---|
| 553 | | } |
|---|
| 554 | | |
|---|
| 555 | | |
|---|
| 556 | | /** |
|---|
| 557 | | * Remove a value in the property registry by name, checking the validity |
|---|
| 558 | | * of the arguments passed. |
|---|
| 559 | | * |
|---|
| 560 | | * @returns iprt status value |
|---|
| 561 | | * @param cParms the number of HGCM parameters supplied |
|---|
| 562 | | * @param paParms the array of HGCM parameters |
|---|
| 563 | | * @thread HGCM |
|---|
| 564 | | */ |
|---|
| 565 | | int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest) |
|---|
| 566 | | { |
|---|
| 567 | | int rc = VINF_SUCCESS; |
|---|
| 568 | | char *pszName; |
|---|
| 569 | | uint32_t cbName; |
|---|
| 570 | | |
|---|
| 571 | | LogFlowThisFunc(("\n")); |
|---|
| 572 | | AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */ |
|---|
| 573 | | |
|---|
| 574 | | /* |
|---|
| 575 | | * Check the user-supplied parameters. |
|---|
| 576 | | */ |
|---|
| 577 | | if ( (cParms != 1) /* Hardcoded value as the next lines depend on it. */ |
|---|
| 578 | | || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */ |
|---|
| 579 | | ) |
|---|
| 580 | | rc = VERR_INVALID_PARAMETER; |
|---|
| 581 | | if (RT_SUCCESS(rc)) |
|---|
| 582 | | rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName); |
|---|
| 583 | | if (RT_SUCCESS(rc)) |
|---|
| 584 | | rc = validateName(pszName, cbName); |
|---|
| 585 | | |
|---|
| 586 | | /* |
|---|
| 587 | | * If the property already exists, check its flags to see if we are allowed |
|---|
| 588 | | * to change it. |
|---|
| 589 | | */ |
|---|
| 590 | | if (RT_SUCCESS(rc)) |
|---|
| 591 | | { |
|---|
| 592 | | uint32_t fFlags = NILFLAG; |
|---|
| 593 | | CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); /* Failure is no problem here. */ |
|---|
| 594 | | if ( (isGuest && (fFlags & RDONLYGUEST)) |
|---|
| 595 | | || (!isGuest && (fFlags & RDONLYHOST)) |
|---|
| 596 | | ) |
|---|
| 597 | | rc = VERR_PERMISSION_DENIED; |
|---|
| 598 | | } |
|---|
| 599 | | |
|---|
| 600 | | /* |
|---|
| 601 | | * And delete the property if all is well. |
|---|
| 602 | | */ |
|---|
| 603 | | if (RT_SUCCESS(rc)) |
|---|
| 604 | | { |
|---|
| 605 | | CFGMR3RemoveValue(mpValueNode, pszName); |
|---|
| 606 | | if (isGuest) |
|---|
| 607 | | notifyHost(pszName); |
|---|
| 608 | | } |
|---|
| 609 | | LogFlowThisFunc(("rc = %Rrc\n", rc)); |
|---|
| 610 | | return rc; |
|---|
| 611 | | } |
|---|
| 612 | | |
|---|
| 613 | | /** |
|---|
| 614 | | * Enumerate guest properties by mask, checking the validity |
|---|
| 615 | | * of the arguments passed. |
|---|
| 616 | | * |
|---|
| 617 | | * @returns iprt status value |
|---|
| 618 | | * @param cParms the number of HGCM parameters supplied |
|---|
| 619 | | * @param paParms the array of HGCM parameters |
|---|
| 620 | | * @thread HGCM |
|---|
| 621 | | */ |
|---|
| 622 | | int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) |
|---|
| 623 | | { |
|---|
| 624 | | /* We reallocate the temporary buffer in which we build up our array in |
|---|
| 625 | | * increments of size BLOCK: */ |
|---|
| 626 | | enum |
|---|
| 627 | | { |
|---|
| 628 | | /* Calculate the increment, not yet rounded down */ |
|---|
| 629 | | BLOCKINCRFULL = (MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 2048), |
|---|
| 630 | | /* And this is the increment after rounding */ |
|---|
| 631 | | BLOCKINCR = BLOCKINCRFULL - BLOCKINCRFULL % 1024 |
|---|
| 632 | | }; |
|---|
| 633 | | int rc = VINF_SUCCESS; |
|---|
| 634 | | |
|---|
| 635 | | /* |
|---|
| 636 | | * Get the HGCM function arguments. |
|---|
| 637 | | */ |
|---|
| 638 | | char *paszPatterns = NULL, *pchBuf = NULL; |
|---|
| 639 | | uint32_t cchPatterns = 0, cchBuf = 0; |
|---|
| 640 | | LogFlowThisFunc(("\n")); |
|---|
| 641 | | AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */ |
|---|
| 642 | | if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */ |
|---|
| 643 | | || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* patterns */ |
|---|
| 644 | | || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* return buffer */ |
|---|
| 645 | | ) |
|---|
| 646 | | rc = VERR_INVALID_PARAMETER; |
|---|
| 647 | | if (RT_SUCCESS(rc)) |
|---|
| 648 | | rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &paszPatterns, &cchPatterns); |
|---|
| 673 | | /* |
|---|
| 674 | | * Next enumerate all values in the current node into a temporary buffer. |
|---|
| 675 | | */ |
|---|
| 676 | | RTMemAutoPtr<char> TmpBuf; |
|---|
| 677 | | uint32_t cchTmpBuf = 0, iTmpBuf = 0; |
|---|
| 678 | | PCFGMLEAF pLeaf = CFGMR3GetFirstValue(mpValueNode); |
|---|
| 679 | | while ((pLeaf != NULL) && RT_SUCCESS(rc)) |
|---|
| 680 | | { |
|---|
| 681 | | /* Reallocate the buffer if it has got too tight */ |
|---|
| 682 | | if (iTmpBuf + BLOCKINCR > cchTmpBuf) |
|---|
| 683 | | { |
|---|
| 684 | | cchTmpBuf += BLOCKINCR * 2; |
|---|
| 685 | | if (!TmpBuf.realloc(cchTmpBuf)) |
|---|
| 686 | | rc = VERR_NO_MEMORY; |
|---|
| 687 | | } |
|---|
| 688 | | /* Fetch the name into the buffer and if it matches one of the |
|---|
| 689 | | * patterns, add its value and an empty timestamp and flags. If it |
|---|
| 690 | | * doesn't match, we simply overwrite it in the buffer. */ |
|---|
| 691 | | if (RT_SUCCESS(rc)) |
|---|
| 692 | | rc = CFGMR3GetValueName(pLeaf, &TmpBuf[iTmpBuf], cchTmpBuf - iTmpBuf); |
|---|
| 693 | | /* Only increment the buffer offest if the name matches, otherwise we |
|---|
| 694 | | * overwrite it next iteration. */ |
|---|
| 695 | | if ( RT_SUCCESS(rc) |
|---|
| 696 | | && ( matchAll |
|---|
| 697 | | || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, |
|---|
| 698 | | &TmpBuf[iTmpBuf], RTSTR_MAX, |
|---|
| 699 | | NULL) |
|---|
| 700 | | ) |
|---|
| | 741 | /* |
|---|
| | 742 | * Next enumerate into a temporary buffer. This can throw, but this is |
|---|
| | 743 | * not a problem as we have nothing to roll back. |
|---|
| | 744 | */ |
|---|
| | 745 | std::string buffer; |
|---|
| | 746 | for (PropertyList::const_iterator it = mProperties.begin(); |
|---|
| | 747 | RT_SUCCESS(rc) && (it != mProperties.end()); ++it) |
|---|
| | 748 | { |
|---|
| | 749 | if ( matchAll |
|---|
| | 750 | || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX, |
|---|
| | 751 | it->mName.c_str(), RTSTR_MAX, NULL) |
|---|