Changeset 69688 in vbox for trunk/src/VBox/Runtime/r3/nt
- Timestamp:
- Nov 14, 2017 2:44:25 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 119060
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp
r69111 r69688 33 33 34 34 #include <iprt/path.h> 35 #include <iprt/mem.h> 35 36 #include <iprt/string.h> 36 37 #include <iprt/err.h> … … 406 407 407 408 /** 409 * Gets the NT path to the object represented by the given handle. 410 * 411 * @returns IPRT status code. 412 * @param pNtName Where to return the NT path. Free using 413 * RTUtf16Alloc. 414 * @param hHandle The handle. 415 * @param cwcExtra How much extra space is needed. 416 */ 417 static int rtNtPathFromHandle(struct _UNICODE_STRING *pNtName, HANDLE hHandle, size_t cwcExtra) 418 { 419 /* 420 * Query the name into a buffer. 421 */ 422 ULONG cbBuf = _2K; 423 PUNICODE_STRING pUniStrBuf = (PUNICODE_STRING)RTMemTmpAllocZ(cbBuf); 424 if (!pUniStrBuf) 425 return VERR_NO_TMP_MEMORY; 426 427 ULONG cbNameBuf = cbBuf; 428 NTSTATUS rcNt = NtQueryObject(hHandle, ObjectNameInformation, pUniStrBuf, cbBuf, &cbNameBuf); 429 while ( rcNt == STATUS_BUFFER_OVERFLOW 430 || rcNt == STATUS_BUFFER_TOO_SMALL) 431 { 432 do 433 cbBuf *= 2; 434 while (cbBuf <= cbNameBuf); 435 RTMemTmpFree(pUniStrBuf); 436 pUniStrBuf = (PUNICODE_STRING)RTMemTmpAllocZ(cbBuf); 437 if (!pUniStrBuf) 438 return VERR_NO_TMP_MEMORY; 439 440 cbNameBuf = cbBuf; 441 rcNt = NtQueryObject(hHandle, ObjectNameInformation, pUniStrBuf, cbBuf, &cbNameBuf); 442 } 443 int rc; 444 if (NT_SUCCESS(rcNt)) 445 { 446 /* 447 * Copy the result into the return string. 448 */ 449 size_t cbNeeded = cwcExtra * sizeof(RTUTF16) + pNtName->Length + sizeof(RTUTF16); 450 if (cbNeeded < _64K) 451 { 452 pNtName->Length = pUniStrBuf->Length; 453 pNtName->MaximumLength = (uint16_t)cbNeeded; 454 pNtName->Buffer = RTUtf16Alloc(cbNeeded); 455 if (pNtName->Buffer) 456 { 457 memcpy(pNtName->Buffer, pUniStrBuf->Buffer, pUniStrBuf->Length); 458 pNtName->Buffer[pUniStrBuf->Length / sizeof(RTUTF16)] = '\0'; 459 rc = VINF_SUCCESS; 460 } 461 else 462 rc = VERR_NO_UTF16_MEMORY; 463 } 464 else 465 rc = VERR_FILENAME_TOO_LONG; 466 } 467 else 468 rc = RTErrConvertFromNtStatus(rcNt); 469 RTMemTmpFree(pUniStrBuf); 470 return rc; 471 } 472 473 474 /** 475 * Rewinds the path back to the start of the previous component. 476 * 477 * Will preserve root slash. 478 * 479 * @returns Pointer to character after the start-of-component slash, or 480 * pwszStart. 481 * @param pwcEnd The current end of the path. 482 * @param pwszStart The start of the path. 483 */ 484 static PRTUTF16 rtNtPathGetPrevComponent(PRTUTF16 pwcEnd, PRTUTF16 pwszStart) 485 { 486 if ((uintptr_t)pwcEnd > (uintptr_t)pwszStart) 487 { 488 RTUTF16 wc = pwcEnd[-1]; 489 if ( (wc == '\\' || wc == '/') 490 && (uintptr_t)(pwcEnd - pwszStart) != 1) 491 pwcEnd--; 492 493 while ( (uintptr_t)pwcEnd > (uintptr_t)pwszStart 494 && (wc = pwcEnd[-1]) != '\\' 495 && (wc = pwcEnd[-1]) != '/') 496 pwcEnd--; 497 } 498 return pwcEnd; 499 } 500 501 502 /** 503 * Converts a relative windows-style path to relative NT format and encoding. 504 * 505 * @returns IPRT status code. 506 * @param pNtName Where to return the NT name. Free using 507 * rtTNtPathToNative with phRootDir set to NULL. 508 * @param phRootDir On input, the handle to the directory the path 509 * is relative to. On output, the handle to 510 * specify as root directory in the object 511 * attributes when accessing the path. If 512 * enmAscent is kRTNtPathRelativeAscent_Allow, it 513 * may have been set to NULL. 514 * @param pszPath The relative UTF-8 path. 515 * @param enmAscent How to handle ascent. 516 */ 517 RTDECL(int) RTNtPathRelativeFromUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath, 518 RTNTPATHRELATIVEASCENT enmAscent) 519 { 520 size_t cwcMax; 521 int rc = RTStrCalcUtf16LenEx(pszPath, RTSTR_MAX, &cwcMax); 522 if (RT_FAILURE(rc)) 523 return rc; 524 if (cwcMax + 2 >= _32K) 525 return VERR_FILENAME_TOO_LONG; 526 527 PRTUTF16 pwszDst; 528 pNtName->Length = 0; 529 pNtName->MaximumLength = (uint16_t)((cwcMax + 2) * sizeof(RTUTF16)); 530 pNtName->Buffer = pwszDst = RTUtf16Alloc((cwcMax + 2) * sizeof(RTUTF16)); 531 if (!pwszDst) 532 return VERR_NO_UTF16_MEMORY; 533 534 PRTUTF16 pwszDstCur = pwszDst; 535 PRTUTF16 pwszDstComp = pwszDst; 536 for (;;) 537 { 538 RTUNICP uc; 539 rc = RTStrGetCpEx(&pszPath, &uc); 540 if (RT_SUCCESS(rc)) 541 { 542 switch (uc) 543 { 544 default: 545 pwszDstCur = RTUtf16PutCp(pwszDst, uc); 546 break; 547 548 case '\\': 549 case '/': 550 if (pwszDstCur != pwszDstComp) 551 pwszDstComp = pwszDstCur = RTUtf16PutCp(pwszDstCur, '\\'); 552 /* else: only one slash between components. */ 553 break; 554 555 case '.': 556 if (pwszDstCur == pwszDstComp) 557 { 558 /* 559 * Single dot changes nothing. 560 */ 561 char ch2 = *pszPath; 562 if (ch2 == '\0') 563 { 564 /* Trailing single dot means we need to drop trailing slash. */ 565 if (pwszDstCur != pwszDst) 566 pwszDstCur--; 567 *pwszDstCur = '\0'; 568 pNtName->Length = (uint16_t)(pwszDstCur - pwszDst); 569 return VINF_SUCCESS; 570 } 571 572 if (ch2 == '\\' || ch2 == '/') 573 { 574 pszPath++; /* Ignore lone dot followed but another component. */ 575 break; 576 } 577 578 /* 579 * Two dots drops off the last directory component. This gets complicated 580 * when we start out without any path and we need to consult enmAscent. 581 */ 582 if (ch2 == '.') 583 { 584 char ch3 = pszPath[1]; 585 if ( ch3 == '\\' 586 || ch3 == '/' 587 || ch3 == '\0') 588 { 589 /* Drop a path component. */ 590 if (pwszDstComp != pwszDst) 591 pwszDstComp = pwszDstCur = rtNtPathGetPrevComponent(pwszDstCur, pwszDst); 592 /* Hit the start, which is a bit complicated. */ 593 else 594 switch (enmAscent) 595 { 596 case kRTNtPathRelativeAscent_Allow: 597 if (*phRootDir != RTNT_INVALID_HANDLE_VALUE) 598 { 599 RTUtf16Free(pwszDst); 600 rc = rtNtPathFromHandle(pNtName, *phRootDir, cwcMax + 2); 601 if (RT_FAILURE(rc)) 602 return rc; 603 604 *phRootDir = RTNT_INVALID_HANDLE_VALUE; 605 pwszDst = pNtName->Buffer; 606 pwszDstCur = &pwszDst[pNtName->Length / sizeof(RTUTF16)]; 607 if ( pwszDst != pwszDstCur 608 && pwszDstCur[-1] != '\\' 609 && pwszDstCur[-1] != '/') 610 *pwszDstCur++ = '\\'; 611 pwszDstComp = pwszDstCur = rtNtPathGetPrevComponent(pwszDstCur, pwszDst); 612 } 613 /* else: ignore attempt to ascend beyond the NT root (won't get here). */ 614 break; 615 616 case kRTNtPathRelativeAscent_Ignore: 617 /* nothing to do here */ 618 break; 619 620 default: 621 case kRTNtPathRelativeAscent_Fail: 622 RTUtf16Free(pwszDst); 623 return VERR_PATH_NOT_FOUND; 624 } 625 626 if (ch3 == '\0') 627 { 628 *pwszDstCur = '\0'; 629 pNtName->Length = (uint16_t)(pwszDstCur - pwszDst); 630 return VINF_SUCCESS; 631 } 632 pszPath += 2; 633 break; 634 } 635 } 636 } 637 638 /* Neither '.' nor '..'. */ 639 pwszDstCur = RTUtf16PutCp(pwszDstCur, '.'); 640 break; 641 642 case '\0': 643 *pwszDstCur = '\0'; 644 pNtName->Length = (uint16_t)(pwszDstCur - pwszDst); 645 return VINF_SUCCESS; 646 } 647 } 648 } 649 } 650 651 652 /** 408 653 * Frees the native path and root handle. 409 654 * 410 655 * @param pNtName The NT path after a successful rtNtPathToNative 411 * call. 412 * @param phRootDir The root handle variable from the same call. 656 * call or RTNtPathRelativeFromUtf8. 657 * @param phRootDir The root handle variable from rtNtPathToNative, 658 * but NOT RTNtPathRelativeFromUtf8. 413 659 */ 414 660 static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir) … … 417 663 pNtName->Buffer = NULL; 418 664 419 RT_NOREF_PV(phRootDir); /* never returned by rtNtPathToNative */665 RT_NOREF_PV(phRootDir); /* never returned by rtNtPathToNative, shouldn't be freed in connection with RTNtPathRelativeFromUtf8 */ 420 666 } 421 667 … … 424 670 * Frees the native path and root handle. 425 671 * 426 * @param pNtName The NT path from a successful RTNtPathToNative427 * or RTNtPathFromWinUtf16Ex call.428 * @param phRootDir The root handle variable from the same call.672 * @param pNtName The NT path after a successful rtNtPathToNative 673 * call or RTNtPathRelativeFromUtf8. 674 * @param phRootDir The root handle variable from rtNtPathToNative, 429 675 */ 430 676 RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
Note:
See TracChangeset
for help on using the changeset viewer.