Changeset 19926 in vbox
- Timestamp:
- May 22, 2009 11:37:39 PM (16 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/path.h
r19924 r19926 299 299 * such as: 300 300 * <ul> 301 * <li>On DOS-like platforms, both |\| and |/| separator charsare considered301 * <li>On DOS-like platforms, both separator chars (|\| and |/|) are considered 302 302 * to be equal. 303 303 * <li>On platforms with case-insensitive file systems, mismatching characters … … 305 305 * </ul> 306 306 * 307 * File system details are currently ignored. This means that you won't get308 * case-insensitive compares on unix systems when a path goes into a case-insensitive309 * filesystem like FAT, HPFS, HFS, NTFS, JFS, or similar. For NT, OS/2 and similar310 * you'll won't get case-sensitive compares on a case-sensitive file system.311 *312 * @param pszPath1 Path to compare (must be an absolute path).313 * @param pszPath2 Path to compare (must be an absolute path).314 *315 307 * @returns @< 0 if the first path less than the second path. 316 308 * @returns 0 if the first path identical to the second path. 317 309 * @returns @> 0 if the first path greater than the second path. 310 * 311 * @param pszPath1 Path to compare (must be an absolute path). 312 * @param pszPath2 Path to compare (must be an absolute path). 313 * 314 * @remarks File system details are currently ignored. This means that you won't 315 * get case-insentive compares on unix systems when a path goes into a 316 * case-insensitive filesystem like FAT, HPFS, HFS, NTFS, JFS, or 317 * similar. For NT, OS/2 and similar you'll won't get case-sensitve 318 * compares on a case-sensitive file system. 318 319 */ 319 320 RTDECL(int) RTPathCompare(const char *pszPath1, const char *pszPath2); … … 322 323 * Checks if a path starts with the given parent path. 323 324 * 324 * This means that either the path and the parent path matches completely, or that325 * th e path is to some file or directory residing in the tree given by the parent326 * directory.325 * This means that either the path and the parent path matches completely, or 326 * that the path is to some file or directory residing in the tree given by the 327 * parent directory. 327 328 * 328 329 * The path comparison takes platform-dependent details into account, 329 330 * see RTPathCompare() for details. 331 * 332 * @returns |true| when \a pszPath starts with \a pszParentPath (or when they 333 * are identical), or |false| otherwise. 330 334 * 331 335 * @param pszPath Path to check, must be an absolute path. … … 333 337 * No trailing directory slash! 334 338 * 335 * @returns |true| when \a pszPath starts with \a pszParentPath (or when they 336 * are identical), or |false| otherwise. 337 * 338 * @remark This API doesn't currently handle root directory compares in a manner 339 * consistent with the other APIs. RTPathStartsWith(pszSomePath, "/") will 340 * not work if pszSomePath isn't "/". 339 * @remarks This API doesn't currently handle root directory compares in a 340 * manner consistant with the other APIs. RTPathStartsWith(pszSomePath, 341 * "/") will not work if pszSomePath isn't "/". 341 342 */ 342 343 RTDECL(bool) RTPathStartsWith(const char *pszPath, const char *pszParentPath); 344 345 /** 346 * Appends one partial path to another. 347 * 348 * The main purpose of this function is to deal correctly with leading and 349 * trailing slashes. 350 * 351 * @returns IPRT status code. 352 * @retval VERR_PATH 353 * 354 * @param pszPath The path to append pszAppend to. This serves as both 355 * input and output. This can be empty, in which case 356 * pszAppend is just copied over. 357 * @param cchPathDst The size of the buffer pszPath points to. This 358 * should NOT be strlen(pszPath). 359 * @param pszAppend The partial path to append to pszPath. This can be 360 * NULL, in which case nothing is done. 361 * 362 * @remarks On OS/2, Window and similar systems, concatenating a drive letter 363 * specifier with a root prefixed path will result in an absolute path. 364 * Meaning, RTPathAppend(strcpy(szBuf, "C:"), sizeof(szBuf), "/bar") 365 * will result in "C:/bar". (This follows directly from the behavior 366 * when pszPath is empty.) 367 */ 368 RTDECL(int) RTPathAppend(char *pszPath, size_t cchPathDst, const char *pszAppend); 343 369 344 370 -
trunk/src/VBox/Runtime/r3/path.cpp
r19924 r19926 448 448 * such as: 449 449 * <ul> 450 * <li>On DOS-like platforms, both |\| and |/| separator charsare considered450 * <li>On DOS-like platforms, both separator chars (|\| and |/|) are considered 451 451 * to be equal. 452 452 * <li>On platforms with case-insensitive file systems, mismatching characters … … 454 454 * </ul> 455 455 * 456 * @remark457 *458 * File system details are currently ignored. This means that you won't get459 * case-insentive compares on unix systems when a path goes into a case-insensitive460 * filesystem like FAT, HPFS, HFS, NTFS, JFS, or similar. For NT, OS/2 and similar461 * you'll won't get case-sensitve compares on a case-sensitive file system.462 *463 * @param pszPath1 Path to compare (must be an absolute path).464 * @param pszPath2 Path to compare (must be an absolute path).465 *466 456 * @returns @< 0 if the first path less than the second path. 467 457 * @returns 0 if the first path identical to the second path. 468 458 * @returns @> 0 if the first path greater than the second path. 459 * 460 * @param pszPath1 Path to compare (must be an absolute path). 461 * @param pszPath2 Path to compare (must be an absolute path). 462 * 463 * @remarks File system details are currently ignored. This means that you won't 464 * get case-insentive compares on unix systems when a path goes into a 465 * case-insensitive filesystem like FAT, HPFS, HFS, NTFS, JFS, or 466 * similar. For NT, OS/2 and similar you'll won't get case-sensitve 467 * compares on a case-sensitive file system. 469 468 */ 470 469 RTDECL(int) RTPathCompare(const char *pszPath1, const char *pszPath2) … … 477 476 * Checks if a path starts with the given parent path. 478 477 * 479 * This means that either the path and the parent path matches completely, or that480 * th e path is to some file or directory residing in the tree given by the parent481 * directory.478 * This means that either the path and the parent path matches completely, or 479 * that the path is to some file or directory residing in the tree given by the 480 * parent directory. 482 481 * 483 482 * The path comparison takes platform-dependent details into account, 484 483 * see RTPathCompare() for details. 484 * 485 * @returns |true| when \a pszPath starts with \a pszParentPath (or when they 486 * are identical), or |false| otherwise. 485 487 * 486 488 * @param pszPath Path to check, must be an absolute path. … … 488 490 * No trailing directory slash! 489 491 * 490 * @returns |true| when \a pszPath starts with \a pszParentPath (or when they 491 * are identical), or |false| otherwise. 492 * 493 * @remark This API doesn't currently handle root directory compares in a manner 494 * consistant with the other APIs. RTPathStartsWith(pszSomePath, "/") will 495 * not work if pszSomePath isn't "/". 492 * @remarks This API doesn't currently handle root directory compares in a 493 * manner consistant with the other APIs. RTPathStartsWith(pszSomePath, 494 * "/") will not work if pszSomePath isn't "/". 496 495 */ 497 496 RTDECL(bool) RTPathStartsWith(const char *pszPath, const char *pszParentPath) … … 542 541 return RTStrDup(szPath); 543 542 return NULL; 543 } 544 545 546 /** 547 * Figures the length of the root part of the path. 548 * 549 * @returns length of the root specifier. 550 * @retval 0 if none. 551 * 552 * @param pszPath The path to investigate. 553 * 554 * @remarks Unnecessary root slashes will not be counted. The caller will have 555 * to deal with it where it matters. 556 */ 557 static size_t rtPathRootSpecLen(const char *pszPath) 558 { 559 /* fend of wildlife. */ 560 if (!pszPath) 561 return 0; 562 563 /* Root slash? */ 564 if (RTPATH_IS_SLASH(pszPath[0])) 565 { 566 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 567 /* UNC? */ 568 if ( RTPATH_IS_SLASH(pszPath[1]) 569 && pszPath[2] != '\0' 570 && !RTPATH_IS_SLASH(pszPath[2])) 571 { 572 /* Find the end of the server name. */ 573 const char *pszEnd = pszPath + 2; 574 pszEnd += 2; 575 while ( *pszEnd != '\0' 576 && !RTPATH_IS_SLASH(*pszEnd)) 577 pszEnd++; 578 if (RTPATH_IS_SLASH(*pszEnd)) 579 { 580 pszEnd++; 581 while (RTPATH_IS_SLASH(*pszEnd)) 582 pszEnd++; 583 584 /* Find the end of the share name */ 585 while ( *pszEnd != '\0' 586 && !RTPATH_IS_SLASH(*pszEnd)) 587 pszEnd++; 588 if (RTPATH_IS_SLASH(*pszEnd)) 589 pszEnd++; 590 return pszPath - pszEnd; 591 } 592 } 593 #endif 594 return 1; 595 } 596 597 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 598 /* Drive specifier? */ 599 if ( pszPath[0] != '\0' 600 && pszPath[1] == ':' 601 && RT_C_IS_ALPHA(pszPath[0])) 602 { 603 if (RTPATH_IS_SLASH(pszPath[2])) 604 return 3; 605 return 2; 606 } 607 #endif 608 return 0; 544 609 } 545 610 … … 664 729 665 730 731 RTDECL(int) RTPathAppend(char *pszPath, size_t cchPath, const char *pszAppend) 732 { 733 char *pszPathEnd = (char *)memchr(pszPath, '\0', cchPath); 734 AssertReturn(pszPathEnd, VERR_INVALID_PARAMETER); 735 736 /* 737 * Special cases. 738 */ 739 if (!pszAppend) 740 return VINF_SUCCESS; 741 size_t cchAppend = strlen(pszAppend); 742 if (!cchAppend) 743 return VINF_SUCCESS; 744 if (pszPathEnd == pszPath) 745 { 746 if (cchAppend >= cchPath) 747 return VERR_BUFFER_OVERFLOW; 748 memcpy(pszPath, pszAppend, cchAppend + 1); 749 return VINF_SUCCESS; 750 } 751 752 /* 753 * Balance slashes and check for buffer overflow. 754 */ 755 bool fAddSlash = false; 756 if (!RTPATH_IS_SLASH(pszPathEnd[-1])) 757 { 758 if (!RTPATH_IS_SLASH(pszAppend[0])) 759 { 760 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 761 if ( pszPath[1] == ':' 762 && RT_C_IS_ALPHA(pszPath[0])) 763 { 764 if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cchPath) 765 return VERR_BUFFER_OVERFLOW; 766 } 767 else 768 #endif 769 { 770 if ((size_t)(pszPathEnd - pszPath) + 1 + cchAppend >= cchPath) 771 return VERR_BUFFER_OVERFLOW; 772 *pszPathEnd++ = '/'; 773 } 774 } 775 else 776 { 777 /* One slash is sufficient at this point. */ 778 while (RTPATH_IS_SLASH(pszAppend[1])) 779 pszAppend++, cchAppend--; 780 781 if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cchPath) 782 return VERR_BUFFER_OVERFLOW; 783 } 784 } 785 else 786 { 787 /* No slashes needed in the appended bit. */ 788 while (RTPATH_IS_SLASH(*pszAppend)) 789 pszAppend++, cchAppend--; 790 791 /* In the leading path we can skip unnecessary trailing slashes, but 792 be sure to leave one. */ 793 size_t const cchRoot = rtPathRootSpecLen(pszPath); 794 while ( (size_t)(pszPathEnd - pszPath) > RT_MAX(1, cchRoot) 795 && RTPATH_IS_SLASH(pszPathEnd[-2])) 796 pszPathEnd--; 797 798 if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cchPath) 799 return VERR_BUFFER_OVERFLOW; 800 } 801 802 /* 803 * What remains now is the just the copying. 804 */ 805 memcpy(pszPathEnd, pszAppend, cchAppend + 1); 806 return VINF_SUCCESS; 807 } 808 809 666 810 #ifndef RT_MINI 667 811 -
trunk/src/VBox/Runtime/testcase/tstPath.cpp
r19925 r19926 45 45 int main() 46 46 { 47 char szPath[RTPATH_MAX]; 48 47 49 /* 48 50 * Init RT+Test. … … 62 64 */ 63 65 RTTestSub(hTest, "RTPathExecDir"); 64 char szPath[RTPATH_MAX];65 66 RTTESTI_CHECK_RC(RTPathExecDir(szPath, sizeof(szPath)), VINF_SUCCESS); 66 67 if (RT_SUCCESS(rc)) … … 232 233 const char *pszInput = s_apszStripFilenameTests[i]; 233 234 const char *pszExpect = s_apszStripFilenameTests[i + 1]; 234 char szPath[RTPATH_MAX];235 235 strcpy(szPath, pszInput); 236 236 RTPathStripFilename(szPath); … … 248 248 * RTPathAppend. 249 249 */ 250 RTTestSub(hTest, "RTPathAppend"); 251 static const char *s_apszAppendTests[] = 252 { 253 /* base append result */ 254 "/", "", "/", 255 "", "/", "/", 256 "/", "/", "/", 257 "/x", "", "/x", 258 "/x", "/", "/x/", 259 "/", "x", "/x", 260 "dir", "file", "dir/file", 261 "dir", "/file", "dir/file", 262 "dir", "//file", "dir/file", 263 "dir", "///file", "dir/file", 264 "dir/", "/file", "dir/file", 265 "dir/", "//file", "dir/file", 266 "dir/", "///file", "dir/file", 267 "dir//", "file", "dir/file", 268 "dir//", "/file", "dir/file", 269 "dir//", "//file", "dir/file", 270 "dir///", "///file", "dir/file", 271 #if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS) 272 "/", "\\", "/", 273 "\\", "/", "\\", 274 "\\\\srv\\shr", "dir//", "\\\\srv\\shr/dir//", 275 "\\\\srv\\shr", "dir//file", "\\\\srv\\shr/dir//file", 276 "\\\\srv\\shr", "//dir//", "\\\\srv\\shr/dir//", 277 "\\\\srv\\shr", "/\\dir//", "\\\\srv\\shr\\dir//", 278 "\\\\", "not-srv/not-shr/file", "\\not-srv/not-shr/file", 279 "C:", "autoexec.bat", "C:autoexec.bat", 280 "C:", "/autoexec.bat", "C:/autoexec.bat", 281 "C:", "\\autoexec.bat", "C:\\autoexec.bat", 282 "C:\\", "/autoexec.bat", "C:\\autoexec.bat", 283 "C:\\\\", "autoexec.bat", "C:\\autoexec.bat", 284 #endif 285 }; 286 for (unsigned i = 0; i < RT_ELEMENTS(s_apszAppendTests); i += 3) 287 { 288 const char *pszInput = s_apszAppendTests[i]; 289 const char *pszAppend = s_apszAppendTests[i + 1]; 290 const char *pszExpect = s_apszAppendTests[i + 2]; 291 strcpy(szPath, pszInput); 292 RTTESTI_CHECK_RC(rc = RTPathAppend(szPath, sizeof(szPath), pszAppend), VINF_SUCCESS); 293 if (RT_FAILURE(rc)) 294 continue; 295 if (strcmp(szPath, pszExpect)) 296 { 297 RTTestIFailed("Unexpected result\n" 298 " input: '%s'\n" 299 " append: '%s'\n" 300 " output: '%s'\n" 301 "expected: '%s'", 302 pszInput, pszAppend, szPath, pszExpect); 303 } 304 else 305 { 306 size_t const cchResult = strlen(szPath); 307 308 strcpy(szPath, pszInput); 309 RTTESTI_CHECK_RC(rc = RTPathAppend(szPath, cchResult + 2, pszAppend), VINF_SUCCESS); 310 RTTESTI_CHECK(RT_FAILURE(rc) || !strcmp(szPath, pszExpect)); 311 312 strcpy(szPath, pszInput); 313 RTTESTI_CHECK_RC(rc = RTPathAppend(szPath, cchResult + 1, pszAppend), VINF_SUCCESS); 314 RTTESTI_CHECK(RT_FAILURE(rc) || !strcmp(szPath, pszExpect)); 315 316 if (strlen(pszInput) < cchResult) 317 { 318 strcpy(szPath, pszInput); 319 RTTESTI_CHECK_RC(RTPathAppend(szPath, cchResult, pszAppend), VERR_BUFFER_OVERFLOW); 320 } 321 } 322 } 250 323 251 324
Note:
See TracChangeset
for help on using the changeset viewer.