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