1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <ctype.h> 29 #include "system.h" 30 31 #ifndef _LIMITS_H 32 #include <limits.h> 33 #endif 34 35 #ifndef _ERRNO_H 36 #include <errno.h> 37 #endif 38 39 #ifndef _STDLIB_H_ 40 #include <stdlib.h> 41 #endif 42 43 #ifndef _STRINGS_H 44 #include <strings.h> 45 #endif 46 47 #ifndef _UNISTD_H 48 #include <unistd.h> 49 #endif 50 #include <osl/file.h> 51 #include <osl/security.h> 52 #include <rtl/uri.h> 53 #include <osl/diagnose.h> 54 #include <rtl/ustring.hxx> 55 #include <rtl/ustrbuf.h> 56 57 #ifndef _OSL_TREAD_H_ 58 #include <osl/thread.h> 59 #endif 60 #include <osl/file.hxx> 61 #include <osl/mutex.h> 62 #include <osl/process.h> 63 #include "file_error_transl.h" 64 65 #ifndef _FILE_URL_H_ 66 #include "file_url.h" 67 #endif 68 #include "file_path_helper.hxx" 69 70 #ifndef _OSL_UUNXAPI_HXX_ 71 #include "uunxapi.hxx" 72 #endif 73 74 #include <wchar.h> 75 #include <wctype.h> 76 77 /*************************************************** 78 79 General note 80 81 This file contains the part that handles File URLs. 82 83 File URLs as scheme specific notion of URIs 84 (RFC2396) may be handled platform independend, but 85 will not in osl which is considered wrong. 86 Future version of osl should handle File URLs this 87 way. In rtl/uri there is already an URI parser etc. 88 so this code should be consolidated. 89 90 **************************************************/ 91 92 oslMutex g_CurrentDirectoryMutex; 93 94 95 /*************************************************** 96 * forward 97 **************************************************/ 98 99 void _osl_warnFile(const char*, rtl_uString*); 100 rtl_uString* oslMakeUStrFromPsz(const sal_Char* pszStr,rtl_uString** uStr); 101 102 extern "C" int UnicodeToText(char *, size_t, const sal_Unicode *, sal_Int32); 103 extern "C" int TextToUnicode(const char* text, size_t text_buffer_size, sal_Unicode* unic_text, sal_Int32 unic_text_buffer_size); 104 105 /*************************************************** 106 * namespace directives 107 **************************************************/ 108 109 using namespace osl; 110 111 /****************************************************************************** 112 * 113 * Exported Module Functions 114 * 115 *****************************************************************************/ 116 117 /* a slightly modified version of Pchar in rtl/source/uri.c */ 118 const sal_Bool uriCharClass[128] = 119 { 120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */ 121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 122 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./ */ 123 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */ 124 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */ 125 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */ 126 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */ 127 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /* pqrstuvwxyz{|}~ */ 128 }; 129 130 131 /* check for top wrong usage strings */ 132 /* 133 static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len ) 134 { 135 rtl_uString *pTmp = NULL; 136 sal_Bool bRet; 137 138 rtl_uString_newFromStr_WithLength( &pTmp, path, len ); 139 140 rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length ); 141 142 bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) || 143 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) || 144 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) || 145 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) || 146 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) ); 147 148 rtl_uString_release( pTmp ); 149 return bRet; 150 } 151 */ 152 153 154 /****************************************************************************/ 155 /* osl_getFileURLFromSystemPath */ 156 /****************************************************************************/ 157 158 BOOL WINAPI IsValidFilePathComponent( 159 LPCTSTR lpComponent, LPCTSTR *lppComponentEnd, DWORD dwFlags) 160 { 161 LPCTSTR lpComponentEnd = NULL; 162 LPCTSTR lpCurrent = lpComponent; 163 BOOL fValid = TRUE; /* Assume success */ 164 TCHAR cLast = 0; 165 166 /* Path component length must not exceed MAX_PATH */ 167 168 while ( !lpComponentEnd && lpCurrent && lpCurrent - lpComponent < _MAX_PATH ) 169 { 170 switch ( *lpCurrent ) 171 { 172 /* Both backslash and slash determine the end of a path component */ 173 case '\0': 174 case '/': 175 case '\\': 176 switch ( cLast ) 177 { 178 /* Component must not end with '.' or blank and can't be empty */ 179 180 case '.': 181 if ( dwFlags & VALIDATEPATH_ALLOW_ELLIPSE ) 182 { 183 if ( 1 == lpCurrent - lpComponent ) 184 { 185 /* Current directory is O.K. */ 186 lpComponentEnd = lpCurrent; 187 break; 188 } 189 else if ( 2 == lpCurrent - lpComponent && '.' == *lpComponent ) 190 { 191 /* Parent directory is O.K. */ 192 lpComponentEnd = lpCurrent; 193 break; 194 } 195 } 196 case 0: 197 case ' ': 198 lpComponentEnd = lpCurrent - 1; 199 fValid = FALSE; 200 break; 201 default: 202 lpComponentEnd = lpCurrent; 203 break; 204 } 205 break; 206 /* '?' and '*' are valid wildcards but not valid file name characters */ 207 case '?': 208 case '*': 209 if ( dwFlags & VALIDATEPATH_ALLOW_WILDCARDS ) 210 break; 211 /* The following characters are reserved */ 212 case '<': 213 case '>': 214 case '\"': 215 case '|': 216 case ':': 217 lpComponentEnd = lpCurrent; 218 fValid = FALSE; 219 break; 220 default: 221 /* Characters below ASCII 32 are not allowed */ 222 if ( *lpCurrent < ' ' ) 223 { 224 lpComponentEnd = lpCurrent; 225 fValid = FALSE; 226 } 227 break; 228 } 229 cLast = *lpCurrent++; 230 } 231 232 /* If we don't reached the end of the component the length of the component was to long 233 ( See condition of while loop ) */ 234 if ( !lpComponentEnd ) 235 { 236 fValid = FALSE; 237 lpComponentEnd = lpCurrent; 238 } 239 240 /* Test wether the component specifies a device name what is not allowed */ 241 242 // MT: PERFORMANCE: 243 // This is very expensive. A lot of calls to _tcsicmp. 244 // in SRC6870m71 67.000 calls of this method while empty office start result into more than 1.500.00 calls of _tcsicmp! 245 // Possible optimizations 246 // - Array should be const static 247 // - Sorted array, use binary search 248 // - More intelligent check for com1-9, lpt1-9 249 // Maybe make szComponent upper case, don't search case intensitive 250 // Talked to HRO: Could be removed. Shouldn't be used in OOo, and if used for something like a filename, it will lead to an error anyway. 251 /* 252 if ( fValid ) 253 { 254 LPCTSTR alpDeviceNames[] = 255 { 256 TEXT("CON"), 257 TEXT("PRN"), 258 TEXT("AUX"), 259 TEXT("CLOCK$"), 260 TEXT("NUL"), 261 TEXT("LPT1"), 262 TEXT("LPT2"), 263 TEXT("LPT3"), 264 TEXT("LPT4"), 265 TEXT("LPT5"), 266 TEXT("LPT6"), 267 TEXT("LPT7"), 268 TEXT("LPT8"), 269 TEXT("LPT9"), 270 TEXT("COM1"), 271 TEXT("COM2"), 272 TEXT("COM3"), 273 TEXT("COM4"), 274 TEXT("COM5"), 275 TEXT("COM6"), 276 TEXT("COM7"), 277 TEXT("COM8"), 278 TEXT("COM9") 279 }; 280 281 TCHAR szComponent[MAX_PATH]; 282 int nComponentLength; 283 LPCTSTR lpDot; 284 int i; 285 286 // A device name with an extension is also invalid 287 lpDot = _tcschr( lpComponent, '.' ); 288 289 if ( !lpDot || lpDot > lpComponentEnd ) 290 nComponentLength = lpComponentEnd - lpComponent; 291 else 292 nComponentLength = lpDot - lpComponent; 293 294 _tcsncpy( szComponent, lpComponent, nComponentLength ); 295 szComponent[nComponentLength] = 0; 296 297 for ( i = 0; i < sizeof( alpDeviceNames ) / sizeof(LPCTSTR); i++ ) 298 { 299 if ( 0 == _tcsicmp( szComponent, alpDeviceNames[i] ) ) 300 { 301 lpComponentEnd = lpComponent; 302 fValid = FALSE; 303 break; 304 } 305 } 306 } 307 */ 308 309 if ( fValid ) 310 { 311 // Empty components are not allowed 312 if ( lpComponentEnd - lpComponent < 1 ) 313 fValid = FALSE; 314 315 // If we reached the end of the string NULL is returned 316 else if ( !*lpComponentEnd ) 317 lpComponentEnd = NULL; 318 319 } 320 321 if ( lppComponentEnd ) 322 *lppComponentEnd = lpComponentEnd; 323 324 return fValid; 325 } 326 327 //##################################################### 328 DWORD WINAPI IsValidFilePath(LPCTSTR lpszPath, LPCTSTR *lppError, DWORD dwFlags) 329 { 330 LPCTSTR lpComponent; 331 BOOL fValid = TRUE; 332 DWORD dwPathType = PATHTYPE_ERROR; 333 334 if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE ) 335 dwFlags |= VALIDATEPATH_ALLOW_ELLIPSE; 336 337 if ( !lpszPath ) 338 { 339 fValid = FALSE; 340 lpComponent = lpszPath; 341 } 342 343 /* Test for UNC path notation */ 344 if ( 2 == _tcsspn( lpszPath, CHARSET_SEPARATOR ) ) 345 { 346 /* Place the pointer behind the leading to backslashes */ 347 348 lpComponent = lpszPath + 2; 349 350 fValid = IsValidFilePathComponent( lpComponent, &lpComponent, VALIDATEPATH_ALLOW_ELLIPSE ); 351 352 /* So far we have a valid servername. Now let's see if we also have a network resource */ 353 354 dwPathType = PATHTYPE_ABSOLUTE_UNC; 355 356 if ( fValid ) 357 { 358 if ( lpComponent && !*++lpComponent ) 359 lpComponent = NULL; 360 361 if ( !lpComponent ) 362 { 363 #if 0 364 /* We only have a Server specification what is invalid */ 365 366 lpComponent = lpszPath; 367 fValid = FALSE; 368 #else 369 dwPathType |= PATHTYPE_IS_SERVER; 370 #endif 371 } 372 else 373 { 374 /* Now test the network resource */ 375 376 fValid = IsValidFilePathComponent( lpComponent, &lpComponent, 0 ); 377 378 /* If we now reached the end of the path, everything is O.K. */ 379 380 381 if ( fValid && (!lpComponent || lpComponent && !*++lpComponent ) ) 382 { 383 lpComponent = NULL; 384 dwPathType |= PATHTYPE_IS_VOLUME; 385 } 386 } 387 } 388 } 389 390 /* Local path verification. Must start with <drive>: */ 391 else if ( _istalpha( lpszPath[0] ) && ':' == lpszPath[1] ) 392 { 393 /* Place pointer behind correct drive specification */ 394 395 lpComponent = lpszPath + 2; 396 397 if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) ) 398 lpComponent++; 399 else if ( *lpComponent ) 400 fValid = FALSE; 401 402 dwPathType = PATHTYPE_ABSOLUTE_LOCAL; 403 404 /* Now we are behind the backslash or it was a simple drive without backslash */ 405 406 if ( fValid && !*lpComponent ) 407 { 408 lpComponent = NULL; 409 dwPathType |= PATHTYPE_IS_VOLUME; 410 } 411 } 412 413 /* Can be a relative path */ 414 else if ( dwFlags & VALIDATEPATH_ALLOW_RELATIVE ) 415 { 416 lpComponent = lpszPath; 417 418 /* Relative path can start with a backslash */ 419 420 if ( 1 == _tcsspn( lpComponent, CHARSET_SEPARATOR ) ) 421 { 422 lpComponent++; 423 if ( !*lpComponent ) 424 lpComponent = NULL; 425 } 426 427 dwPathType = PATHTYPE_RELATIVE; 428 } 429 430 /* Anything else is an error */ 431 else 432 { 433 fValid = FALSE; 434 lpComponent = lpszPath; 435 } 436 437 /* Now validate each component of the path */ 438 while ( fValid && lpComponent ) 439 { 440 fValid = IsValidFilePathComponent( lpComponent, &lpComponent, dwFlags ); 441 442 if ( fValid && lpComponent ) 443 { 444 lpComponent++; 445 446 /* If the string behind the backslash is empty, we've done */ 447 448 if ( !*lpComponent ) 449 lpComponent = NULL; 450 } 451 } 452 453 if ( fValid && _tcslen( lpszPath ) >= _MAX_PATH ) 454 { 455 fValid = FALSE; 456 lpComponent = lpszPath + _MAX_PATH; 457 } 458 459 if ( lppError ) 460 *lppError = lpComponent; 461 462 return fValid ? dwPathType : PATHTYPE_ERROR; 463 } 464 465 sal_Bool _osl_decodeURL( rtl_String* strUTF8, rtl_uString** pstrDecodedURL ) 466 { 467 sal_Char *pBuffer; 468 const sal_Char *pSrcEnd; 469 const sal_Char *pSrc; 470 sal_Char *pDest; 471 sal_Int32 nSrcLen; 472 sal_Bool bValidEncoded = sal_True; /* Assume success */ 473 474 /* The resulting decoded string length is shorter or equal to the source length */ 475 476 nSrcLen = rtl_string_getLength(strUTF8); 477 pBuffer = reinterpret_cast<sal_Char*>(rtl_allocateMemory(nSrcLen + 1)); 478 479 pDest = pBuffer; 480 pSrc = rtl_string_getStr(strUTF8); 481 pSrcEnd = pSrc + nSrcLen; 482 483 /* Now decode the URL what should result in an UTF8 string */ 484 while ( bValidEncoded && pSrc < pSrcEnd ) 485 { 486 switch ( *pSrc ) 487 { 488 case '%': 489 { 490 sal_Char aToken[3]; 491 sal_Char aChar; 492 493 pSrc++; 494 aToken[0] = *pSrc++; 495 aToken[1] = *pSrc++; 496 aToken[2] = 0; 497 498 aChar = (sal_Char)strtoul( aToken, NULL, 16 ); 499 500 /* The chars are path delimiters and must not be encoded */ 501 502 if ( 0 == aChar || '\\' == aChar || '/' == aChar || ':' == aChar ) 503 bValidEncoded = sal_False; 504 else 505 *pDest++ = aChar; 506 } 507 break; 508 default: 509 *pDest++ = *pSrc++; 510 break; 511 } 512 } 513 514 *pDest++ = 0; 515 516 if ( bValidEncoded ) { 517 rtl_string2UString( pstrDecodedURL, pBuffer, rtl_str_getLength(pBuffer), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); 518 OSL_ASSERT(*pstrDecodedURL != 0); 519 } 520 521 rtl_freeMemory( pBuffer ); 522 523 return bValidEncoded; 524 } 525 526 //############################################# 527 void _osl_encodeURL( rtl_uString *strURL, rtl_String **pstrEncodedURL ) 528 { 529 /* Encode non ascii characters within the URL */ 530 531 rtl_String *strUTF8 = NULL; 532 sal_Char *pszEncodedURL; 533 const sal_Char *pURLScan; 534 sal_Char *pURLDest; 535 sal_Int32 nURLScanLen; 536 sal_Int32 nURLScanCount; 537 538 rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); 539 540 pszEncodedURL = (sal_Char*) rtl_allocateMemory( (rtl_string_getLength( strUTF8 ) * 3 + 1) * sizeof(sal_Char) ); 541 542 pURLDest = pszEncodedURL; 543 pURLScan = rtl_string_getStr( strUTF8 ); 544 nURLScanLen = rtl_string_getLength( strUTF8 ); 545 nURLScanCount = 0; 546 547 while ( nURLScanCount < nURLScanLen ) 548 { 549 sal_Char cCurrent = *pURLScan; 550 551 switch ( cCurrent ) 552 { 553 default: 554 if (!( ( cCurrent >= 'a' && cCurrent <= 'z' ) || ( cCurrent >= 'A' && cCurrent <= 'Z' ) || ( cCurrent >= '0' && cCurrent <= '9' ) ) ) 555 { 556 sprintf( pURLDest, "%%%02X", (unsigned char)cCurrent ); 557 pURLDest += 3; 558 break; 559 } 560 case '!': 561 case '\'': 562 case '(': 563 case ')': 564 case '*': 565 case '-': 566 case '.': 567 case '_': 568 case '~': 569 case '$': 570 case '&': 571 case '+': 572 case ',': 573 case '=': 574 case '@': 575 case ':': 576 case '/': 577 case '\\': 578 case '|': 579 *pURLDest++ = cCurrent; 580 break; 581 case 0: 582 break; 583 } 584 585 pURLScan++; 586 nURLScanCount++; 587 } 588 589 590 *pURLDest = 0; 591 592 rtl_string_release( strUTF8 ); 593 rtl_string_newFromStr( pstrEncodedURL, pszEncodedURL ); 594 rtl_freeMemory( pszEncodedURL ); 595 } 596 597 //############################################# 598 oslFileError SAL_CALL _osl_getFileURLFromSystemPath( rtl_uString* strPath, rtl_uString** pstrURL ) 599 { 600 oslFileError nError = osl_File_E_INVAL; /* Assume failure */ 601 rtl_uString *strTempURL = NULL; 602 DWORD dwPathType = PATHTYPE_ERROR; 603 604 if (strPath) 605 dwPathType = IsValidFilePath(strPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE); 606 607 if (dwPathType) 608 { 609 rtl_uString *strTempPath = NULL; 610 611 /* Replace backslashes */ 612 613 rtl_uString_newReplace( &strTempPath, strPath, '\\', '/' ); 614 615 switch ( dwPathType & PATHTYPE_MASK_TYPE ) 616 { 617 case PATHTYPE_RELATIVE: 618 rtl_uString_assign( &strTempURL, strTempPath ); 619 nError = osl_File_E_None; 620 break; 621 case PATHTYPE_ABSOLUTE_UNC: 622 rtl_uString_newFromAscii( &strTempURL, "file:" ); 623 rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath ); 624 nError = osl_File_E_None; 625 break; 626 case PATHTYPE_ABSOLUTE_LOCAL: 627 rtl_uString_newFromAscii( &strTempURL, "file:///" ); 628 rtl_uString_newConcat( &strTempURL, strTempURL, strTempPath ); 629 nError = osl_File_E_None; 630 break; 631 default: 632 break; 633 } 634 635 /* Release temp path */ 636 637 rtl_uString_release( strTempPath ); 638 } 639 640 if ( osl_File_E_None == nError ) 641 { 642 rtl_String *strEncodedURL = NULL; 643 644 /* Encode the URL */ 645 646 _osl_encodeURL( strTempURL, &strEncodedURL ); 647 648 /* Provide URL via unicode string */ 649 650 rtl_string2UString( pstrURL, rtl_string_getStr(strEncodedURL), rtl_string_getLength(strEncodedURL), RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS ); 651 OSL_ASSERT(*pstrURL != 0); 652 rtl_string_release( strEncodedURL ); 653 } 654 655 /* Release temp URL */ 656 657 if ( strTempURL ) 658 rtl_uString_release( strTempURL ); 659 660 /* 661 OSL_ENSURE_FILE( !nError, "osl_getFileURLFromSystemPath: \"%s\" is not a systemPath !!!", strPath ); 662 */ 663 664 return nError; 665 } 666 667 oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL ) 668 { 669 return _osl_getFileURLFromSystemPath( ustrSystemPath, pustrFileURL ); 670 #if 0 671 static const sal_Unicode pDoubleSlash[2] = { '/', '/' }; 672 673 rtl_uString *pTmp = NULL; 674 sal_Int32 nIndex; 675 676 if( 0 == ustrSystemPath->length ) 677 return osl_File_E_INVAL; 678 679 /* YD convert '\' to '/' */ 680 rtl_ustr_replaceChar( ustrSystemPath->buffer, '\\', '/' ); 681 682 /* temporary hack: if already file url, return ustrSystemPath */ 683 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) ) 684 { 685 /* 686 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) ) 687 { 688 OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" ); 689 rtl_uString_assign( pustrFileURL, ustrSystemPath ); 690 } 691 else 692 { 693 rtl_uString *pTmp2 = NULL; 694 695 OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" ); 696 rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 ); 697 rtl_uString_newFromAscii( &pTmp2, "file://" ); 698 rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 ); 699 rtl_uString_release( pTmp2 ); 700 } 701 return osl_File_E_None; 702 */ 703 return osl_File_E_INVAL; 704 } 705 706 707 /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ 708 if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] ) 709 { 710 /* check if another user is specified */ 711 if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) ) 712 { 713 /* osl_getHomeDir returns file URL */ 714 osl_getHomeDir( osl_getCurrentSecurity(), &pTmp ); 715 716 /* remove "file://" prefix */ 717 rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 ); 718 719 /* replace '~' in original string */ 720 rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp ); 721 } 722 723 else 724 { 725 /* FIXME: replace ~user with users home directory */ 726 return osl_File_E_INVAL; 727 } 728 } 729 730 /* check if initial string contains double instances of '/' */ 731 nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 ); 732 if( -1 != nIndex ) 733 { 734 sal_Int32 nSrcIndex; 735 sal_Int32 nDeleted = 0; 736 737 /* if pTmp is not already allocated, copy ustrSystemPath for modification */ 738 if( NULL == pTmp ) 739 rtl_uString_newFromString( &pTmp, ustrSystemPath ); 740 741 /* adapt index to pTmp */ 742 nIndex += pTmp->length - ustrSystemPath->length; 743 744 /* remove all occurances of '//' */ 745 for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ ) 746 { 747 if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) ) 748 nDeleted++; 749 else 750 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex]; 751 } 752 753 /* adjust length member */ 754 pTmp->length -= nDeleted; 755 } 756 757 if( NULL == pTmp ) 758 rtl_uString_assign( &pTmp, ustrSystemPath ); 759 760 /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ 761 /* 762 OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); 763 */ 764 765 /* file URLs must be URI encoded */ 766 rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL ); 767 768 rtl_uString_release( pTmp ); 769 770 /* absolute urls should start with 'file://' */ 771 if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] ) 772 { 773 rtl_uString *pProtocol = NULL; 774 775 rtl_uString_newFromAscii( &pProtocol, "file://" ); 776 rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL ); 777 rtl_uString_release( pProtocol ); 778 } 779 780 return osl_File_E_None; 781 #endif 782 } 783 784 //############################################# 785 oslFileError SAL_CALL _osl_getSystemPathFromFileURL( rtl_uString *strURL, rtl_uString **pustrPath, sal_Bool bAllowRelative ) 786 { 787 rtl_String *strUTF8 = NULL; 788 rtl_uString *strDecodedURL = NULL; 789 rtl_uString *strTempPath = NULL; 790 const sal_Unicode *pDecodedURL; 791 sal_uInt32 nDecodedLen; 792 sal_Bool bValidEncoded; 793 oslFileError nError = osl_File_E_INVAL; /* Assume failure */ 794 795 /* If someone hasn't encoded the complete URL we convert it to UTF8 now to prevent from 796 having a mixed encoded URL later */ 797 798 rtl_uString2String( &strUTF8, rtl_uString_getStr( strURL ), rtl_uString_getLength( strURL ), RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS ); 799 800 /* If the length of strUTF8 and strURL differs it indicates that the URL was not correct encoded */ 801 802 OSL_ENSURE_FILE( 803 strUTF8->length == strURL->length || 804 0 != rtl_ustr_ascii_shortenedCompare_WithLength( strURL->buffer, strURL->length, "file:\\\\", 7 ) 805 ,"osl_getSystemPathFromFileURL: \"%s\" is not encoded !!!", strURL ); 806 807 bValidEncoded = _osl_decodeURL( strUTF8, &strDecodedURL ); 808 809 /* Release the encoded UTF8 string */ 810 811 rtl_string_release( strUTF8 ); 812 813 814 if ( bValidEncoded ) 815 { 816 /* Replace backslashes and pipes */ 817 818 rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '/', '\\' ); 819 rtl_uString_newReplace( &strDecodedURL, strDecodedURL, '|', ':' ); 820 821 pDecodedURL = rtl_uString_getStr( strDecodedURL ); 822 nDecodedLen = rtl_uString_getLength( strDecodedURL ); 823 824 /* Must start with "file://" */ 825 826 if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\", 7 ) ) 827 { 828 sal_uInt32 nSkip; 829 830 if ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\\\", 8 ) ) 831 nSkip = 8; 832 else if ( 833 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\localhost\\", 17 ) || 834 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pDecodedURL, nDecodedLen, "file:\\\\127.0.0.1\\", 17 ) 835 ) 836 nSkip = 17; 837 else 838 nSkip = 5; 839 840 /* Indicates local root */ 841 if ( nDecodedLen == nSkip ) 842 rtl_uString_newFromStr_WithLength( &strTempPath, (const sal_Unicode*)WSTR_SYSTEM_ROOT_PATH, ELEMENTS_OF_ARRAY(WSTR_SYSTEM_ROOT_PATH) - 1 ); 843 else 844 rtl_uString_newFromStr_WithLength( &strTempPath, pDecodedURL + nSkip, nDecodedLen - nSkip ); 845 846 if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_ELLIPSE ) ) 847 nError = osl_File_E_None; 848 } 849 else if ( bAllowRelative ) /* This maybe a relative file URL */ 850 { 851 rtl_uString_assign( &strTempPath, strDecodedURL ); 852 853 if ( IsValidFilePath( strTempPath->buffer, NULL, VALIDATEPATH_ALLOW_RELATIVE | VALIDATEPATH_ALLOW_ELLIPSE ) ) 854 nError = osl_File_E_None; 855 } 856 /* 857 else 858 OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not an absolute FileURL !!!", strURL ); 859 */ 860 861 } 862 863 if ( strDecodedURL ) 864 rtl_uString_release( strDecodedURL ); 865 866 if ( osl_File_E_None == nError ) 867 rtl_uString_assign( pustrPath, strTempPath ); 868 869 if ( strTempPath ) 870 rtl_uString_release( strTempPath ); 871 872 /* 873 OSL_ENSURE_FILE( !nError, "osl_getSystemPathFromFileURL: \"%s\" is not a FileURL !!!", strURL ); 874 */ 875 876 return nError; 877 } 878 879 /****************************************************************************/ 880 /* osl_getSystemPathFromFileURL */ 881 /****************************************************************************/ 882 883 oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath ) 884 { 885 return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, sal_True ); 886 #if 0 887 sal_Int32 nIndex = 0; 888 rtl_uString * pTmp = NULL; 889 890 sal_Unicode encodedSlash[3] = { '%', '2', 'F' }; 891 892 /* temporary hack: if already system path, return ustrFileURL */ 893 /* 894 if( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) 895 { 896 OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" ); 897 rtl_uString_assign( pustrSystemPath, ustrFileURL ); 898 return osl_File_E_None; 899 } 900 */ 901 902 /* a valid file url may not start with '/' */ 903 if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) ) 904 { 905 return osl_File_E_INVAL; 906 } 907 908 /* search for encoded slashes (%2F) and decode every single token if we find one */ 909 if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) ) 910 { 911 rtl_uString * ustrPathToken = NULL; 912 sal_Int32 nOffset = 7; 913 914 do 915 { 916 nOffset += nIndex; 917 918 /* break url down in '/' devided tokens tokens */ 919 nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' ); 920 921 /* copy token to new string */ 922 rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset, 923 -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ ); 924 925 /* decode token */ 926 rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); 927 928 /* the result should not contain any '/' */ 929 if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) ) 930 { 931 rtl_uString_release( pTmp ); 932 rtl_uString_release( ustrPathToken ); 933 934 return osl_File_E_INVAL; 935 } 936 937 } while( -1 != nIndex ); 938 939 /* release temporary string and restore index variable */ 940 rtl_uString_release( ustrPathToken ); 941 nIndex = 0; 942 } 943 944 /* protocol and server should not be encoded, so decode the whole string */ 945 rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); 946 947 /* check if file protocol specified */ 948 /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ 949 if( 7 <= pTmp->length ) 950 { 951 rtl_uString * pProtocol = NULL; 952 rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 ); 953 954 /* protocol is case insensitive */ 955 rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length ); 956 957 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) ) 958 nIndex = 7; 959 960 rtl_uString_release( pProtocol ); 961 } 962 963 /* skip "localhost" or "127.0.0.1" if "file://" is specified */ 964 /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ 965 if( nIndex && ( 10 <= pTmp->length - nIndex ) ) 966 { 967 rtl_uString * pServer = NULL; 968 rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 ); 969 970 /* server is case insensitive */ 971 rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length ); 972 973 if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) || 974 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) ) 975 { 976 /* don't exclude the '/' */ 977 nIndex += 9; 978 } 979 980 rtl_uString_release( pServer ); 981 } 982 983 if( nIndex ) 984 rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex ); 985 986 /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ 987 if( (sal_Unicode) '~' == pTmp->buffer[0] ) 988 { 989 /* check if another user is specified */ 990 if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) ) 991 { 992 rtl_uString *pTmp2 = NULL; 993 994 /* osl_getHomeDir returns file URL */ 995 osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 ); 996 997 /* remove "file://" prefix */ 998 rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 ); 999 1000 /* replace '~' in original string */ 1001 rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 ); 1002 rtl_uString_release( pTmp2 ); 1003 } 1004 1005 else 1006 { 1007 /* FIXME: replace ~user with users home directory */ 1008 return osl_File_E_INVAL; 1009 } 1010 } 1011 1012 /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ 1013 /* 1014 OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); 1015 */ 1016 1017 *pustrSystemPath = pTmp; 1018 return osl_File_E_None; 1019 #endif // 0 1020 } 1021 1022 1023 /**************************************************************************** 1024 * osl_getSystemPathFromFileURL_Ex - helper function 1025 * clients may specify if they want to accept relative 1026 * URLs or not 1027 ****************************************************************************/ 1028 1029 oslFileError osl_getSystemPathFromFileURL_Ex( 1030 rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative) 1031 { 1032 return _osl_getSystemPathFromFileURL( ustrFileURL, pustrSystemPath, bAllowRelative); 1033 #if 0 1034 rtl_uString* temp = 0; 1035 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp); 1036 1037 if (osl_File_E_None == osl_error) 1038 { 1039 if (bAllowRelative 1040 || (UNICHAR_SLASH == temp->buffer[0]) 1041 || (UNICHAR_COLON == temp->buffer[1] && UNICHAR_SLASH == temp->buffer[2])) 1042 { 1043 *pustrSystemPath = temp; 1044 } 1045 else 1046 { 1047 rtl_uString_release(temp); 1048 osl_error = osl_File_E_INVAL; 1049 } 1050 } 1051 1052 return osl_error; 1053 #endif 1054 } 1055 1056 namespace /* private */ 1057 { 1058 1059 #if 0 // YD 1060 1061 /****************************************************** 1062 * Helper function, return a pinter to the final '\0' 1063 * of a string 1064 ******************************************************/ 1065 1066 sal_Unicode* ustrtoend(sal_Unicode* pStr) 1067 { 1068 return (pStr + rtl_ustr_getLength(pStr)); 1069 } 1070 1071 /********************************************* 1072 1073 ********************************************/ 1074 sal_Unicode* ustrcpy(const sal_Unicode* s, sal_Unicode* d) 1075 { 1076 const sal_Unicode* sc = s; 1077 sal_Unicode* dc = d; 1078 1079 while ((*dc++ = *sc++)) 1080 /**/; 1081 1082 return d; 1083 } 1084 1085 /********************************************* 1086 1087 ********************************************/ 1088 1089 sal_Unicode* ustrncpy(const sal_Unicode* s, sal_Unicode* d, unsigned int n) 1090 { 1091 const sal_Unicode* sc = s; 1092 sal_Unicode* dc = d; 1093 unsigned int i = n; 1094 1095 while (i--) 1096 *dc++ = *sc++; 1097 1098 if (n) 1099 *dc = 0; 1100 1101 return d; 1102 } 1103 1104 /********************************************* 1105 1106 ********************************************/ 1107 1108 sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d) 1109 { 1110 sal_Unicode* p = ustrtoend(d); 1111 *p++ = chr; 1112 *p = 0; 1113 return d; 1114 } 1115 1116 /********************************************* 1117 1118 ********************************************/ 1119 1120 sal_Unicode* ustrcat(const sal_Unicode* s, sal_Unicode* d) 1121 { 1122 sal_Unicode* dc = ustrtoend(d); 1123 ustrcpy(s, dc); 1124 return d; 1125 } 1126 1127 /****************************************************** 1128 * 1129 ******************************************************/ 1130 1131 bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr) 1132 { 1133 sal_Unicode* p = ustrtoend(pStr); 1134 if (p > pStr) 1135 p--; 1136 return (*p == Chr); 1137 } 1138 1139 /****************************************************** 1140 * Ensure that the given string has the specified last 1141 * character if necessary append it 1142 ******************************************************/ 1143 1144 sal_Unicode* _strensurelast(sal_Unicode* pStr, sal_Unicode Chr) 1145 { 1146 if (!_islastchr(pStr, Chr)) 1147 ustrchrcat(Chr, pStr); 1148 return pStr; 1149 } 1150 1151 /****************************************************** 1152 * Remove the last part of a path, a path that has 1153 * only a '/' or no '/' at all will be returned 1154 * unmodified 1155 ******************************************************/ 1156 1157 sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath) 1158 { 1159 /* we always may skip -2 because we 1160 may at least stand on a '/' but 1161 either there is no other character 1162 before this '/' or it's another 1163 character than the '/' 1164 */ 1165 sal_Unicode* p = ustrtoend(aPath) - 2; 1166 1167 // move back to the next path separator 1168 // or to the start of the string 1169 while ((p > aPath) && (*p != UNICHAR_SLASH)) 1170 p--; 1171 1172 if (p >= aPath) 1173 { 1174 if (UNICHAR_SLASH == *p) 1175 { 1176 p++; 1177 *p = '\0'; 1178 } 1179 else 1180 { 1181 *p = '\0'; 1182 } 1183 } 1184 1185 return aPath; 1186 } 1187 1188 /****************************************************** 1189 * 1190 ******************************************************/ 1191 1192 oslFileError _osl_resolvepath( 1193 /*inout*/ sal_Unicode* path, 1194 /*inout*/ sal_Unicode* current_pos, 1195 /*in */ sal_Unicode* sentinel, 1196 /*inout*/ bool* failed) 1197 { 1198 oslFileError ferr = osl_File_E_None; 1199 1200 if (!*failed) 1201 { 1202 char unresolved_path[PATH_MAX]; 1203 if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path))) 1204 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 1205 1206 char resolved_path[PATH_MAX]; 1207 if (realpath(unresolved_path, resolved_path)) 1208 { 1209 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX)) 1210 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 1211 1212 current_pos = ustrtoend(path) - 1; 1213 } 1214 else 1215 { 1216 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno) 1217 *failed = true; 1218 else 1219 ferr = oslTranslateFileError(OSL_FET_ERROR, errno); 1220 } 1221 } 1222 1223 return ferr; 1224 } 1225 1226 /****************************************************** 1227 * Works even with non existing paths. The resulting 1228 * path must not exceed PATH_MAX else 1229 * osl_File_E_NAMETOOLONG is the result 1230 ******************************************************/ 1231 1232 oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path) 1233 { 1234 // the given unresolved path must not exceed PATH_MAX 1235 if (unresolved_path.getLength() >= (PATH_MAX - 2)) 1236 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 1237 1238 sal_Unicode path_resolved_so_far[PATH_MAX]; 1239 const sal_Unicode* punresolved = unresolved_path.getStr(); 1240 sal_Unicode* presolvedsf = path_resolved_so_far; 1241 1242 // reserve space for leading '/' and trailing '\0' 1243 // do not exceed this limit 1244 sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2; 1245 1246 // if realpath fails with error ENOTDIR, EACCES or ENOENT 1247 // we will not call it again, because _osl_realpath should also 1248 // work with non existing directories etc. 1249 bool realpath_failed = false; 1250 oslFileError ferr; 1251 1252 path_resolved_so_far[0] = '\0'; 1253 1254 while (*punresolved != '\0') 1255 { 1256 // ignore '/.' , skip one part back when '/..' 1257 1258 if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf)) 1259 { 1260 if ('\0' == *(punresolved + 1)) 1261 { 1262 punresolved++; 1263 continue; 1264 } 1265 else if (UNICHAR_SLASH == *(punresolved + 1)) 1266 { 1267 punresolved += 2; 1268 continue; 1269 } 1270 else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2)))) 1271 { 1272 _rmlastpathtoken(path_resolved_so_far); 1273 1274 presolvedsf = ustrtoend(path_resolved_so_far) - 1; 1275 1276 if (UNICHAR_SLASH == *(punresolved + 2)) 1277 punresolved += 3; 1278 else 1279 punresolved += 2; 1280 1281 continue; 1282 } 1283 else // a file or directory name may start with '.' 1284 { 1285 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 1286 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 1287 1288 ustrchrcat(*punresolved++, path_resolved_so_far); 1289 1290 if ('\0' == *punresolved && !realpath_failed) 1291 { 1292 ferr = _osl_resolvepath( 1293 path_resolved_so_far, 1294 presolvedsf, 1295 sentinel, 1296 &realpath_failed); 1297 1298 if (osl_File_E_None != ferr) 1299 return ferr; 1300 } 1301 } 1302 } 1303 else if (UNICHAR_SLASH == *punresolved) 1304 { 1305 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 1306 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 1307 1308 ustrchrcat(*punresolved++, path_resolved_so_far); 1309 1310 if (!realpath_failed) 1311 { 1312 ferr = _osl_resolvepath( 1313 path_resolved_so_far, 1314 presolvedsf, 1315 sentinel, 1316 &realpath_failed); 1317 1318 if (osl_File_E_None != ferr) 1319 return ferr; 1320 1321 if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH)) 1322 { 1323 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 1324 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 1325 1326 ustrchrcat(UNICHAR_SLASH, path_resolved_so_far); 1327 } 1328 } 1329 } 1330 else // any other character 1331 { 1332 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 1333 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 1334 1335 ustrchrcat(*punresolved++, path_resolved_so_far); 1336 1337 if ('\0' == *punresolved && !realpath_failed) 1338 { 1339 ferr = _osl_resolvepath( 1340 path_resolved_so_far, 1341 presolvedsf, 1342 sentinel, 1343 &realpath_failed); 1344 1345 if (osl_File_E_None != ferr) 1346 return ferr; 1347 } 1348 } 1349 } 1350 1351 sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far); 1352 1353 OSL_ASSERT(len < PATH_MAX); 1354 1355 resolved_path = rtl::OUString(path_resolved_so_far, len); 1356 1357 return osl_File_E_None; 1358 } 1359 1360 #endif // 0 // YD 1361 1362 } // end namespace private 1363 1364 #if OSL_DEBUG_LEVEL > 0 1365 1366 //##################################################### 1367 void _osl_warnFile( const char *message, rtl_uString *ustrFile ) 1368 { 1369 char szBuffer[2048]; 1370 1371 if (ustrFile) 1372 { 1373 rtl_String *strFile = NULL; 1374 1375 rtl_uString2String( &strFile, rtl_uString_getStr( ustrFile ), rtl_uString_getLength( ustrFile ), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS ); 1376 snprintf( szBuffer, sizeof(szBuffer), message, strFile->buffer ); 1377 rtl_string_release( strFile ); 1378 1379 message = szBuffer; 1380 } 1381 OSL_ENSURE( 0, message ); 1382 } 1383 1384 #endif // OSL_DEBUG_LEVEL > 0 1385 1386 /****************************************************** 1387 * osl_getAbsoluteFileURL 1388 ******************************************************/ 1389 1390 //oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL) 1391 oslFileError SAL_CALL osl_getAbsoluteFileURL( rtl_uString* ustrBaseURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL ) 1392 { 1393 oslFileError eError; 1394 rtl_uString *ustrRelSysPath = NULL; 1395 rtl_uString *ustrBaseSysPath = NULL; 1396 1397 if ( ustrBaseURL && ustrBaseURL->length ) 1398 { 1399 eError = _osl_getSystemPathFromFileURL( ustrBaseURL, &ustrBaseSysPath, sal_False ); 1400 OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with relative or invalid base URL" ); 1401 1402 eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_True ); 1403 } 1404 else 1405 { 1406 eError = _osl_getSystemPathFromFileURL( ustrRelativeURL, &ustrRelSysPath, sal_False ); 1407 OSL_ENSURE( osl_File_E_None == eError, "osl_getAbsoluteFileURL called with empty base URL and/or invalid relative URL" ); 1408 } 1409 1410 if ( !eError ) 1411 { 1412 CHAR szBuffer[_MAX_PATH]; 1413 CHAR szRelSysPath[_MAX_PATH]; 1414 CHAR szCurrentDir[_MAX_PATH]; 1415 int result; 1416 char* cwd; 1417 int rc; 1418 1419 /*@@@ToDo 1420 Bad, bad hack, this only works if the base path 1421 really exists which is not necessary according 1422 to RFC2396 1423 The whole FileURL implementation should be merged 1424 with the rtl/uri class. 1425 */ 1426 if ( ustrBaseSysPath ) 1427 { 1428 CHAR szBaseSysPath[_MAX_PATH]; 1429 1430 if (!g_CurrentDirectoryMutex) 1431 g_CurrentDirectoryMutex = osl_createMutex(); 1432 1433 osl_acquireMutex( g_CurrentDirectoryMutex ); 1434 1435 cwd = getcwd( szCurrentDir, sizeof(szCurrentDir) ); 1436 UnicodeToText( szBaseSysPath, sizeof(szBaseSysPath), ustrBaseSysPath->buffer, ustrBaseSysPath->length); 1437 rc = chdir( szBaseSysPath); 1438 } 1439 1440 UnicodeToText( szRelSysPath, sizeof(szRelSysPath), ustrRelSysPath->buffer, ustrRelSysPath->length); 1441 result = !_abspath( szBuffer, szRelSysPath, sizeof(szBuffer)); 1442 1443 if ( ustrBaseSysPath ) 1444 { 1445 rc = chdir( szCurrentDir ); 1446 1447 osl_releaseMutex( g_CurrentDirectoryMutex ); 1448 } 1449 1450 if ( result ) 1451 { 1452 rtl_uString *ustrAbsSysPath = NULL; 1453 1454 oslMakeUStrFromPsz( szBuffer, &ustrAbsSysPath); 1455 1456 eError = osl_getFileURLFromSystemPath( ustrAbsSysPath, pustrAbsoluteURL ); 1457 1458 if ( ustrAbsSysPath ) 1459 rtl_uString_release( ustrAbsSysPath ); 1460 } 1461 else 1462 eError = osl_File_E_INVAL; 1463 } 1464 1465 if ( ustrBaseSysPath ) 1466 rtl_uString_release( ustrBaseSysPath ); 1467 1468 if ( ustrRelSysPath ) 1469 rtl_uString_release( ustrRelSysPath ); 1470 1471 return eError; 1472 #if 0 1473 FileBase::RC rc; 1474 rtl::OUString unresolved_path; 1475 1476 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path); 1477 1478 if(FileBase::E_None != rc) 1479 return oslFileError(rc); 1480 1481 if (systemPathIsRelativePath(unresolved_path)) 1482 { 1483 rtl::OUString base_path; 1484 rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False); 1485 1486 if (FileBase::E_None != rc) 1487 return oslFileError(rc); 1488 1489 rtl::OUString abs_path; 1490 systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path); 1491 1492 unresolved_path = abs_path; 1493 } 1494 1495 rtl::OUString resolved_path; 1496 rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path); 1497 1498 if (FileBase::E_None == rc) 1499 { 1500 rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL); 1501 OSL_ASSERT(FileBase::E_None == rc); 1502 } 1503 1504 return oslFileError(rc); 1505 #endif // 0 1506 } 1507 1508 1509 namespace /* private */ 1510 { 1511 1512 /********************************************* 1513 No separate error code if unicode to text 1514 conversion or getenv fails because for the 1515 caller there is no difference why a file 1516 could not be found in $PATH 1517 ********************************************/ 1518 1519 bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result) 1520 { 1521 bool bfound = false; 1522 rtl::OUString path = rtl::OUString::createFromAscii("PATH"); 1523 rtl::OUString env_path; 1524 1525 if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData)) 1526 bfound = osl::searchPath(file_path, env_path, result); 1527 1528 return bfound; 1529 } 1530 1531 /********************************************* 1532 No separate error code if unicode to text 1533 conversion or getcwd fails because for the 1534 caller there is no difference why a file 1535 could not be found in CDW 1536 ********************************************/ 1537 1538 bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result) 1539 { 1540 bool bfound = false; 1541 rtl::OUString cwd_url; 1542 1543 if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData)) 1544 { 1545 rtl::OUString cwd; 1546 FileBase::getSystemPathFromFileURL(cwd_url, cwd); 1547 bfound = osl::searchPath(file_path, cwd, result); 1548 } 1549 return bfound; 1550 } 1551 1552 /********************************************* 1553 1554 ********************************************/ 1555 1556 bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result) 1557 { 1558 return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result)); 1559 } 1560 1561 } // end namespace private 1562 1563 1564 /**************************************************************************** 1565 * osl_searchFileURL 1566 ***************************************************************************/ 1567 1568 oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL) 1569 { 1570 OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter"); 1571 1572 FileBase::RC rc; 1573 rtl::OUString file_path; 1574 1575 // try to interpret search path as file url else assume it's a system path list 1576 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path); 1577 if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc)) 1578 file_path = ustrFilePath; 1579 else if (FileBase::E_None != rc) 1580 return oslFileError(rc); 1581 1582 bool bfound = false; 1583 rtl::OUString result; 1584 1585 if (find_in_searchPath(file_path, ustrSearchPath, result) || 1586 find_in_PATH(file_path, result) || 1587 find_in_CWD(file_path, result)) 1588 { 1589 rtl::OUString resolved; 1590 1591 if (osl::realpath(result, resolved)) 1592 { 1593 #if OSL_DEBUG_LEVEL > 0 1594 oslFileError osl_error = 1595 #endif 1596 osl_getFileURLFromSystemPath(resolved.pData, pustrURL); 1597 OSL_ASSERT(osl_File_E_None == osl_error); 1598 bfound = true; 1599 } 1600 } 1601 return bfound ? osl_File_E_None : osl_File_E_NOENT; 1602 } 1603 1604 1605 /**************************************************************************** 1606 * FileURLToPath 1607 ***************************************************************************/ 1608 1609 oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL) 1610 { 1611 rtl_uString* ustrSystemPath = NULL; 1612 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath); 1613 1614 if(osl_File_E_None != osl_error) 1615 return osl_error; 1616 1617 osl_systemPathRemoveSeparator(ustrSystemPath); 1618 1619 /* convert unicode path to text */ 1620 if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length)) 1621 osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); 1622 1623 rtl_uString_release(ustrSystemPath); 1624 1625 return osl_error; 1626 } 1627