- Timestamp:
- Oct 16, 2008 6:38:52 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibGuestProp.cpp
r13291 r13355 272 272 uint32_t *pcbBufActual) 273 273 { 274 /* 275 * Create the GET_PROP message and call the host. 276 */ 274 277 GetProperty Msg; 275 278 … … 278 281 Msg.hdr.u32Function = GET_PROP; 279 282 Msg.hdr.cParms = 4; 280 VbglHGCMParmPtrSet(&Msg.name, const_cast<char *>(pszName), 281 strlen(pszName) + 1); 283 VbglHGCMParmPtrSet(&Msg.name, const_cast<char *>(pszName), strlen(pszName) + 1); 282 284 VbglHGCMParmPtrSet(&Msg.buffer, pvBuf, cbBuf); 283 285 VbglHGCMParmUInt64Set(&Msg.timestamp, 0); … … 287 289 if (RT_SUCCESS(rc)) 288 290 rc = Msg.hdr.result; 289 if ((VERR_BUFFER_OVERFLOW == rc) && (pcbBufActual != NULL)) 291 292 /* 293 * The cbBufActual parameter is also returned on overflow so the call can 294 * adjust his/her buffer. 295 */ 296 if ( rc == VERR_BUFFER_OVERFLOW 297 || pcbBufActual != NULL) 290 298 { 291 299 int rc2 = VbglHGCMParmUInt32Get(&Msg.size, pcbBufActual); 292 if (!RT_SUCCESS(rc2)) 293 rc = rc2; 294 } 295 if (RT_SUCCESS(rc) && (pu64Timestamp != NULL)) 300 AssertRCReturn(rc2, RT_FAILURE(rc) ? rc : rc2); 301 } 302 if (RT_FAILURE(rc)) 303 return rc; 304 305 /* 306 * Buffer layout: Value\0Flags\0. 307 * 308 * If the caller cares about any of these strings, make sure things are 309 * propertly terminated (paranoia). 310 */ 311 if ( RT_SUCCESS(rc) 312 && (ppszValue != NULL || ppszFlags != NULL)) 313 { 314 /* Validate / skip 'Name'. */ 315 char *pszFlags = (char *)memchr(pvBuf, '\0', cbBuf) + 1; 316 AssertPtrReturn(pszFlags, VERR_TOO_MUCH_DATA); 317 if (ppszValue) 318 *ppszValue = (char *)pvBuf; 319 320 if (ppszFlags) 321 { 322 /* Validate 'Flags'. */ 323 void *pvEos = memchr(pszFlags, '\0', cbBuf - (pszFlags - (char *)pvBuf)); 324 AssertPtrReturn(pvEos, VERR_TOO_MUCH_DATA); 325 *ppszFlags = pszFlags; 326 } 327 } 328 329 /* And the timestamp, if requested. */ 330 if (pu64Timestamp != NULL) 331 { 296 332 rc = VbglHGCMParmUInt64Get(&Msg.timestamp, pu64Timestamp); 297 if (RT_SUCCESS(rc) && (ppszValue != NULL)) 298 *ppszValue = reinterpret_cast<char *>(pvBuf); 299 if (RT_SUCCESS(rc) && (ppszFlags != NULL)) 300 { 301 char *pszEos = reinterpret_cast<char *>(memchr(pvBuf, '\0', cbBuf)); 302 if (pszEos) 303 *ppszFlags = pszEos + 1; 304 else 305 rc = VERR_TOO_MUCH_DATA; 306 } 307 return rc; 333 AssertRCReturn(rc, rc); 334 } 335 336 return VINF_SUCCESS; 308 337 } 309 338 … … 517 546 * VbglR3GuestPropEnumFree when it is no longer needed. 518 547 * @param ppszName Where to store the first property name on success. 519 * Should not be freed. 548 * Should not be freed. Optional. 520 549 * @param ppszValue Where to store the first property value on success. 521 * Should not be freed. 550 * Should not be freed. Optional. 522 551 * @param ppszValue Where to store the first timestamp value on success. 552 * Optional. 523 553 * @param ppszFlags Where to store the first flags value on success. 524 * Should not be freed. 554 * Should not be freed. Optional. 525 555 */ 526 556 VBGLR3DECL(int) VbglR3GuestPropEnum(uint32_t u32ClientId, … … 533 563 char const **ppszFlags) 534 564 { 535 int rc = VINF_SUCCESS;565 /* Create the handle. */ 536 566 RTMemAutoPtr<VBGLR3GUESTPROPENUM, VbglR3GuestPropEnumFree> Handle; 537 567 Handle = (PVBGLR3GUESTPROPENUM)RTMemAllocZ(sizeof(VBGLR3GUESTPROPENUM)); 538 568 if (!Handle) 539 r c =VERR_NO_MEMORY;569 return VERR_NO_MEMORY; 540 570 541 571 /* Get the length of the pattern string, including the final terminator. */ … … 560 590 uint32_t cchBuf = 4096; 561 591 RTMemAutoPtr<char> Buf; 592 562 593 /* In reading the guest property data we are racing against the host 563 594 * adding more of it, so loop a few times and retry on overflow. */ 564 bool finish = false; 595 int rc = VINF_SUCCESS; 596 for (int i = 0; i < 10; ++i) 597 { 598 if (!Buf.realloc(cchBuf)) 599 { 600 rc = VERR_NO_MEMORY; 601 break; 602 } 603 rc = VbglR3GuestPropEnumRaw(u32ClientId, Patterns.get(), 604 Buf.get(), cchBuf, &cchBuf); 605 if (rc != VERR_BUFFER_OVERFLOW) 606 break; 607 cchBuf += 4096; /* Just to increase our chances */ 608 } 565 609 if (RT_SUCCESS(rc)) 566 for (int i = 0; (i < 10) && !finish; ++i) 567 { 568 if (!Buf.realloc(cchBuf)) 569 rc = VERR_NO_MEMORY; 570 if (RT_SUCCESS(rc) || (VERR_BUFFER_OVERFLOW == rc)) 571 rc = VbglR3GuestPropEnumRaw(u32ClientId, Patterns.get(), 572 Buf.get(), cchBuf, &cchBuf); 573 if (rc != VERR_BUFFER_OVERFLOW) 574 finish = true; 575 else 576 cchBuf += 4096; /* Just to increase our chances */ 577 } 578 if (VERR_BUFFER_OVERFLOW == rc) 579 rc = VERR_TOO_MUCH_DATA; 580 if (RT_SUCCESS(rc)) 581 { 582 /* Transfer ownership of the buffer to the handle structure. */ 610 { 611 /* 612 * Transfer ownership of the buffer to the handle structure and 613 * call VbglR3GuestPropEnumNext to retriev the first entry. 614 */ 583 615 Handle->pchNext = Handle->pchBuf = Buf.release(); 584 616 Handle->pchBufEnd = Handle->pchBuf + cchBuf; 585 } 586 if (RT_SUCCESS(rc)) 617 618 const char *pszNameTmp; 619 if (!ppszName) 620 ppszName = &pszNameTmp; 587 621 rc = VbglR3GuestPropEnumNext(Handle.get(), ppszName, ppszValue, 588 622 pu64Timestamp, ppszFlags); 589 if (RT_SUCCESS(rc) && (NULL == ppszName)) 590 /* No matching properties found */ 591 rc = VERR_NOT_FOUND; 592 /* And transfer ownership of the handle to the caller. */ 593 if (RT_SUCCESS(rc)) 594 *ppHandle = Handle.release(); 595 return rc; 596 } 597 598 599 /** 600 * Get the next guest property. See @a VbglR3GuestPropEnum. 623 if (RT_SUCCESS(rc) && *ppszName != NULL) 624 *ppHandle = Handle.release(); 625 else if (RT_SUCCESS(rc)) 626 rc = VERR_NOT_FOUND; /* No matching properties found. */ 627 } 628 else if (rc == VERR_BUFFER_OVERFLOW) 629 rc = VERR_TOO_MUCH_DATA; 630 return rc; 631 } 632 633 634 /** 635 * Get the next guest property. 636 * 637 * See @a VbglR3GuestPropEnum. 601 638 * 602 639 * @returns VBox status code. … … 605 642 * @param ppszName Where to store the next property name. This will be 606 643 * set to NULL if there are no more properties to 607 * enumerate. This pointer should not be freed. 644 * enumerate. This pointer should not be freed. Optional. 608 645 * @param ppszValue Where to store the next property value. This will be 609 646 * set to NULL if there are no more properties to 610 * enumerate. This pointer should not be freed. 647 * enumerate. This pointer should not be freed. Optional. 611 648 * @param pu64Timestamp Where to store the next property timestamp. This 612 649 * will be set to zero if there are no more properties 613 * to enumerate. 650 * to enumerate. Optional. 614 651 * @param ppszFlags Where to store the next property flags. This will be 615 652 * set to NULL if there are no more properties to 616 * enumerate. This pointer should not be freed. 653 * enumerate. This pointer should not be freed. Optional. 654 * 655 * @remarks While all output parameters are optional, you need at least one to 656 * figure out when to stop. 617 657 */ 618 658 VBGLR3DECL(int) VbglR3GuestPropEnumNext(PVBGLR3GUESTPROPENUM pHandle, … … 622 662 char const **ppszFlags) 623 663 { 624 /* The VBGLR3GUESTPROPENUM structure contains a buffer containing the raw 664 /* 665 * The VBGLR3GUESTPROPENUM structure contains a buffer containing the raw 625 666 * properties data and a pointer into the buffer which tracks how far we 626 667 * have parsed so far. The buffer contains packed strings in groups of … … 628 669 * terminated by four empty strings. We can rely on this layout unless 629 670 * the caller has been poking about in the structure internals, in which 630 * case they must take responsibility for the results. */ 631 632 /* Get the pointer into the buffer to the next entry. */ 633 char *pchNext = pHandle->pchNext; 634 /* And the pointer to the end of the buffer. */ 635 char *pchLast = pHandle->pchBufEnd; 636 /* The index will initially point to the next name entry. */ 637 char *pszName = pchNext; 638 /* The value for this property starts after the terminator for the name. */ 639 char *pszValue = pchNext = (char *)memchr(pchNext, '\0', pchLast - pchNext) + 1; 640 AssertPtr(pchNext); /* 0x1 is also an invalid pointer :) */ 641 /* The timestamp after the value... */ 642 char *pszTimestamp = pchNext = (char *)memchr(pchNext, '\0', pchLast - pchNext) + 1; 643 AssertPtr(pchNext); 644 /* ...and the flags after the timestamp. */ 645 char *pszFlags = pchNext = (char *)memchr(pchNext, '\0', pchLast - pchNext) + 1; 646 AssertPtr(pchNext); 647 uint64_t u64Timestamp = RTStrToUInt64(pszTimestamp); 648 /* Only move the index pointer in the structure if we found a non-empty entry. */ 671 * case they must take responsibility for the results. 672 * 673 * Layout: 674 * Name\0Value\0Timestamp\0Flags\0 675 */ 676 char *pchNext = pHandle->pchNext; /* The cursor. */ 677 char *pchEnd = pHandle->pchBufEnd; /* End of buffer, for size calculations. */ 678 679 char *pszName = pchNext; 680 char *pszValue = pchNext = (char *)memchr(pchNext, '\0', pchEnd - pchNext) + 1; 681 AssertPtrReturn(pchNext, VERR_PARSE_ERROR); /* 0x1 is also an invalid pointer :) */ 682 683 char *pszTimestamp = pchNext = (char *)memchr(pchNext, '\0', pchEnd - pchNext) + 1; 684 AssertPtrReturn(pchNext, VERR_PARSE_ERROR); 685 686 char *pszFlags = pchNext = (char *)memchr(pchNext, '\0', pchEnd - pchNext) + 1; 687 AssertPtrReturn(pchNext, VERR_PARSE_ERROR); 688 689 /* 690 * Don't move the index pointer if we found the terminating "\0\0\0\0" entry. 691 * Don't try convert the timestamp either. 692 */ 693 uint64_t u64Timestamp; 649 694 if (*pszName != '\0') 650 695 { 651 pHandle->pchNext = pchNext = (char *)memchr(pchNext, '\0', pchLast - pchNext) + 1; 696 pchNext = (char *)memchr(pchNext, '\0', pchEnd - pchNext) + 1; 697 AssertPtrReturn(pchNext, VERR_PARSE_ERROR); 698 699 /* Convert the timestamp string into a number. */ 700 int rc = RTStrToUInt64Full(pszTimestamp, 0, &u64Timestamp); 701 AssertRCSuccessReturn(rc, VERR_PARSE_ERROR); 702 703 pHandle->pchNext = pchNext; 652 704 AssertPtr(pchNext); 653 705 } 654 /* And make sure that the buffer terminator is correct. */ 655 Assert( (*pszName != '\0') 656 || (('\0' == *pszValue) && ('\0' == *pszTimestamp) && ('\0' == *pszFlags)) 657 ); 658 *ppszName = *pszName != '\0' ? pszName : NULL; 659 *ppszValue = *pszValue != '\0' ? pszValue : NULL; 660 *pu64Timestamp = u64Timestamp; 661 *ppszFlags = *pszFlags != '\0' ? pszFlags : NULL; 706 else 707 { 708 u64Timestamp = 0; 709 AssertMsgReturn(!*pszValue && !*pszTimestamp && !*pszFlags, 710 ("'%s' '%s' '%s'\n", pszValue, pszTimestamp, pszFlags), 711 VERR_PARSE_ERROR); 712 } 713 714 /* 715 * Everything is fine, set the return values. 716 */ 717 if (ppszName) 718 *ppszName = *pszName != '\0' ? pszName : NULL; 719 if (ppszValue) 720 *ppszValue = *pszValue != '\0' ? pszValue : NULL; 721 if (pu64Timestamp) 722 *pu64Timestamp = u64Timestamp; 723 if (ppszFlags) 724 *ppszFlags = *pszFlags != '\0' ? pszFlags : NULL; 662 725 return VINF_SUCCESS; 663 726 }
Note:
See TracChangeset
for help on using the changeset viewer.