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 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sal.hxx" 26 27 #include "file_url.h" 28 29 #include "system.h" 30 31 #include <limits.h> 32 #include <errno.h> 33 #include <strings.h> 34 #include <unistd.h> 35 36 #include "osl/file.hxx" 37 #include <osl/security.h> 38 #include <osl/diagnose.h> 39 #include <osl/thread.h> 40 #include <osl/process.h> 41 42 #include <rtl/uri.h> 43 #include <rtl/ustring.hxx> 44 #include <rtl/ustrbuf.h> 45 #include "rtl/textcvt.h" 46 47 #include "file_error_transl.h" 48 #include "file_path_helper.hxx" 49 50 #include "uunxapi.hxx" 51 52 /*************************************************** 53 54 General note 55 56 This file contains the part that handles File URLs. 57 58 File URLs as scheme specific notion of URIs 59 (RFC2396) may be handled platform independend, but 60 will not in osl which is considered wrong. 61 Future version of osl should handle File URLs this 62 way. In rtl/uri there is already an URI parser etc. 63 so this code should be consolidated. 64 65 **************************************************/ 66 /************************************************************************ 67 * ToDo 68 * 69 * Fix osl_getCanonicalName 70 * 71 ***********************************************************************/ 72 73 74 /*************************************************** 75 * namespace directives 76 **************************************************/ 77 78 using namespace osl; 79 80 /*************************************************** 81 * constants 82 **************************************************/ 83 84 const sal_Unicode UNICHAR_SLASH = ((sal_Unicode)'/'); 85 const sal_Unicode UNICHAR_COLON = ((sal_Unicode)':'); 86 const sal_Unicode UNICHAR_DOT = ((sal_Unicode)'.'); 87 88 /****************************************************************************** 89 * 90 * Exported Module Functions 91 * 92 *****************************************************************************/ 93 94 /* a slightly modified version of Pchar in rtl/source/uri.c */ 95 const sal_Bool uriCharClass[128] = 96 { 97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */ 98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./ */ 100 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */ 101 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */ 102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */ 103 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */ 104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /* pqrstuvwxyz{|}~ */ 105 }; 106 107 108 /* check for top wrong usage strings */ 109 /* 110 static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len ) 111 { 112 rtl_uString *pTmp = NULL; 113 sal_Bool bRet; 114 115 rtl_uString_newFromStr_WithLength( &pTmp, path, len ); 116 117 rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length ); 118 119 bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) || 120 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) || 121 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) || 122 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) || 123 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) ); 124 125 rtl_uString_release( pTmp ); 126 return bRet; 127 } 128 */ 129 130 /****************************************************************************/ 131 /* osl_getCanonicalName */ 132 /****************************************************************************/ 133 134 oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL ) 135 { 136 OSL_ENSURE(0, "osl_getCanonicalName not implemented"); 137 138 rtl_uString_newFromString(pustrValidURL, ustrFileURL); 139 return osl_File_E_None; 140 } 141 142 /****************************************************************************/ 143 /* osl_getSystemPathFromFileURL */ 144 /****************************************************************************/ 145 146 oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath ) 147 { 148 sal_Int32 nIndex; 149 rtl_uString * pTmp = NULL; 150 151 sal_Unicode encodedSlash[3] = { '%', '2', 'F' }; 152 sal_Unicode protocolDelimiter[3] = { ':', '/', '/' }; 153 154 /* temporary hack: if already system path, return ustrFileURL */ 155 /* 156 if( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) 157 { 158 OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" ); 159 rtl_uString_assign( pustrSystemPath, ustrFileURL ); 160 return osl_File_E_None; 161 } 162 */ 163 164 /* a valid file url may not start with '/' */ 165 if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) ) 166 { 167 return osl_File_E_INVAL; 168 } 169 170 /* Check for non file:// protocols */ 171 172 nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 ); 173 if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) ) 174 { 175 return osl_File_E_INVAL; 176 } 177 178 /* search for encoded slashes (%2F) and decode every single token if we find one */ 179 180 nIndex = 0; 181 182 if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) ) 183 { 184 rtl_uString * ustrPathToken = NULL; 185 sal_Int32 nOffset = 7; 186 187 do 188 { 189 nOffset += nIndex; 190 191 /* break url down in '/' divided tokens tokens */ 192 nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' ); 193 194 /* copy token to new string */ 195 rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset, 196 -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ ); 197 198 /* decode token */ 199 rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); 200 201 /* the result should not contain any '/' */ 202 if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) ) 203 { 204 rtl_uString_release( pTmp ); 205 rtl_uString_release( ustrPathToken ); 206 207 return osl_File_E_INVAL; 208 } 209 210 } while( -1 != nIndex ); 211 212 /* release temporary string and restore index variable */ 213 rtl_uString_release( ustrPathToken ); 214 nIndex = 0; 215 } 216 217 /* protocol and server should not be encoded, so decode the whole string */ 218 rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp ); 219 220 /* check if file protocol specified */ 221 /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ 222 if( 7 <= pTmp->length ) 223 { 224 rtl_uString * pProtocol = NULL; 225 rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 ); 226 227 /* protocol is case insensitive */ 228 rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length ); 229 230 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) ) 231 nIndex = 7; 232 233 rtl_uString_release( pProtocol ); 234 } 235 236 /* skip "localhost" or "127.0.0.1" if "file://" is specified */ 237 /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */ 238 if( nIndex && ( 10 <= pTmp->length - nIndex ) ) 239 { 240 rtl_uString * pServer = NULL; 241 rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 ); 242 243 /* server is case insensitive */ 244 rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length ); 245 246 if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) || 247 ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) ) 248 { 249 /* don't exclude the '/' */ 250 nIndex += 9; 251 } 252 253 rtl_uString_release( pServer ); 254 } 255 256 if( nIndex ) 257 rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex ); 258 259 /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ 260 if( (sal_Unicode) '~' == pTmp->buffer[0] ) 261 { 262 /* check if another user is specified */ 263 if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) ) 264 { 265 rtl_uString *pTmp2 = NULL; 266 oslSecurity pSecTemp; 267 268 /* osl_getHomeDir returns file URL */ 269 osl_getHomeDir( pSecTemp = osl_getCurrentSecurity(), &pTmp2 ); 270 osl_freeSecurityHandle( pSecTemp ); 271 272 /* remove "file://" prefix */ 273 rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 ); 274 275 /* replace '~' in original string */ 276 rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 ); 277 rtl_uString_release( pTmp2 ); 278 } 279 280 else 281 { 282 /* FIXME: replace ~user with users home directory */ 283 return osl_File_E_INVAL; 284 } 285 } 286 287 /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ 288 /* 289 OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); 290 */ 291 292 *pustrSystemPath = pTmp; 293 return osl_File_E_None; 294 } 295 296 /****************************************************************************/ 297 /* osl_getFileURLFromSystemPath */ 298 /****************************************************************************/ 299 300 oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL ) 301 { 302 static const sal_Unicode pDoubleSlash[2] = { '/', '/' }; 303 304 rtl_uString *pTmp = NULL; 305 sal_Int32 nIndex; 306 307 if( 0 == ustrSystemPath->length ) 308 return osl_File_E_INVAL; 309 310 /* temporary hack: if already file url, return ustrSystemPath */ 311 312 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) ) 313 { 314 /* 315 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) ) 316 { 317 OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" ); 318 rtl_uString_assign( pustrFileURL, ustrSystemPath ); 319 } 320 else 321 { 322 rtl_uString *pTmp2 = NULL; 323 324 OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" ); 325 rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 ); 326 rtl_uString_newFromAscii( &pTmp2, "file://" ); 327 rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 ); 328 rtl_uString_release( pTmp2 ); 329 } 330 return osl_File_E_None; 331 */ 332 return osl_File_E_INVAL; 333 } 334 335 336 /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ 337 if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] ) 338 { 339 /* check if another user is specified */ 340 if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) ) 341 { 342 /* osl_getHomeDir returns file URL */ 343 osl_getHomeDir( osl_getCurrentSecurity(), &pTmp ); 344 345 /* remove "file://" prefix */ 346 rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 ); 347 348 /* replace '~' in original string */ 349 rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp ); 350 } 351 352 else 353 { 354 /* FIXME: replace ~user with users home directory */ 355 return osl_File_E_INVAL; 356 } 357 } 358 359 /* check if initial string contains double instances of '/' */ 360 nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 ); 361 if( -1 != nIndex ) 362 { 363 sal_Int32 nSrcIndex; 364 sal_Int32 nDeleted = 0; 365 366 /* if pTmp is not already allocated, copy ustrSystemPath for modification */ 367 if( NULL == pTmp ) 368 rtl_uString_newFromString( &pTmp, ustrSystemPath ); 369 370 /* adapt index to pTmp */ 371 nIndex += pTmp->length - ustrSystemPath->length; 372 373 /* remove all occurrences of '//' */ 374 for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ ) 375 { 376 if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) ) 377 nDeleted++; 378 else 379 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex]; 380 } 381 382 /* adjust length member */ 383 pTmp->length -= nDeleted; 384 } 385 386 if( NULL == pTmp ) 387 rtl_uString_assign( &pTmp, ustrSystemPath ); 388 389 /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ 390 /* 391 OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); 392 */ 393 394 /* file URLs must be URI encoded */ 395 rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL ); 396 397 rtl_uString_release( pTmp ); 398 399 /* absolute urls should start with 'file://' */ 400 if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] ) 401 { 402 rtl_uString *pProtocol = NULL; 403 404 rtl_uString_newFromAscii( &pProtocol, "file://" ); 405 rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL ); 406 rtl_uString_release( pProtocol ); 407 } 408 409 return osl_File_E_None; 410 } 411 412 /**************************************************************************** 413 * osl_getSystemPathFromFileURL_Ex - helper function 414 * clients may specify if they want to accept relative 415 * URLs or not 416 ****************************************************************************/ 417 418 oslFileError osl_getSystemPathFromFileURL_Ex( 419 rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative) 420 { 421 rtl_uString* temp = 0; 422 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp); 423 424 if (osl_File_E_None == osl_error) 425 { 426 if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0])) 427 { 428 *pustrSystemPath = temp; 429 } 430 else 431 { 432 rtl_uString_release(temp); 433 osl_error = osl_File_E_INVAL; 434 } 435 } 436 437 return osl_error; 438 } 439 440 namespace /* private */ 441 { 442 443 /****************************************************** 444 * Helper function, return a pinter to the final '\0' 445 * of a string 446 ******************************************************/ 447 448 sal_Unicode* ustrtoend(sal_Unicode* pStr) 449 { 450 return (pStr + rtl_ustr_getLength(pStr)); 451 } 452 453 /********************************************* 454 455 ********************************************/ 456 457 sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d) 458 { 459 sal_Unicode* p = ustrtoend(d); 460 *p++ = chr; 461 *p = 0; 462 return d; 463 } 464 465 /****************************************************** 466 * 467 ******************************************************/ 468 469 bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr) 470 { 471 sal_Unicode* p = ustrtoend(pStr); 472 if (p > pStr) 473 p--; 474 return (*p == Chr); 475 } 476 477 /****************************************************** 478 * Remove the last part of a path, a path that has 479 * only a '/' or no '/' at all will be returned 480 * unmodified 481 ******************************************************/ 482 483 sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath) 484 { 485 /* we always may skip -2 because we 486 may at least stand on a '/' but 487 either there is no other character 488 before this '/' or it's another 489 character than the '/' 490 */ 491 sal_Unicode* p = ustrtoend(aPath) - 2; 492 493 // move back to the next path separator 494 // or to the start of the string 495 while ((p > aPath) && (*p != UNICHAR_SLASH)) 496 p--; 497 498 if (p >= aPath) 499 { 500 if (UNICHAR_SLASH == *p) 501 { 502 p++; 503 *p = '\0'; 504 } 505 else 506 { 507 *p = '\0'; 508 } 509 } 510 511 return aPath; 512 } 513 514 /****************************************************** 515 * 516 ******************************************************/ 517 518 oslFileError _osl_resolvepath( 519 /*inout*/ sal_Unicode* path, 520 /*inout*/ sal_Unicode* current_pos, 521 /*inout*/ bool* failed) 522 { 523 oslFileError ferr = osl_File_E_None; 524 525 if (!*failed) 526 { 527 char unresolved_path[PATH_MAX]; 528 if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path))) 529 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 530 531 char resolved_path[PATH_MAX]; 532 if (realpath(unresolved_path, resolved_path)) 533 { 534 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX)) 535 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 536 537 current_pos = ustrtoend(path) - 1; 538 } 539 else 540 { 541 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno) 542 *failed = true; 543 else 544 ferr = oslTranslateFileError(OSL_FET_ERROR, errno); 545 } 546 } 547 548 return ferr; 549 } 550 551 /****************************************************** 552 * Works even with non existing paths. The resulting 553 * path must not exceed PATH_MAX else 554 * osl_File_E_NAMETOOLONG is the result 555 ******************************************************/ 556 557 oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path) 558 { 559 // the given unresolved path must not exceed PATH_MAX 560 if (unresolved_path.getLength() >= (PATH_MAX - 2)) 561 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 562 563 sal_Unicode path_resolved_so_far[PATH_MAX]; 564 const sal_Unicode* punresolved = unresolved_path.getStr(); 565 sal_Unicode* presolvedsf = path_resolved_so_far; 566 567 // reserve space for leading '/' and trailing '\0' 568 // do not exceed this limit 569 sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2; 570 571 // if realpath fails with error ENOTDIR, EACCES or ENOENT 572 // we will not call it again, because _osl_realpath should also 573 // work with non existing directories etc. 574 bool realpath_failed = false; 575 oslFileError ferr; 576 577 path_resolved_so_far[0] = '\0'; 578 579 while (*punresolved != '\0') 580 { 581 // ignore '/.' , skip one part back when '/..' 582 583 if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf)) 584 { 585 if ('\0' == *(punresolved + 1)) 586 { 587 punresolved++; 588 continue; 589 } 590 else if (UNICHAR_SLASH == *(punresolved + 1)) 591 { 592 punresolved += 2; 593 continue; 594 } 595 else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2)))) 596 { 597 _rmlastpathtoken(path_resolved_so_far); 598 599 presolvedsf = ustrtoend(path_resolved_so_far) - 1; 600 601 if (UNICHAR_SLASH == *(punresolved + 2)) 602 punresolved += 3; 603 else 604 punresolved += 2; 605 606 continue; 607 } 608 else // a file or directory name may start with '.' 609 { 610 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 611 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 612 613 ustrchrcat(*punresolved++, path_resolved_so_far); 614 615 if ('\0' == *punresolved && !realpath_failed) 616 { 617 ferr = _osl_resolvepath( 618 path_resolved_so_far, 619 presolvedsf, 620 &realpath_failed); 621 622 if (osl_File_E_None != ferr) 623 return ferr; 624 } 625 } 626 } 627 else if (UNICHAR_SLASH == *punresolved) 628 { 629 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 630 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 631 632 ustrchrcat(*punresolved++, path_resolved_so_far); 633 634 if (!realpath_failed) 635 { 636 ferr = _osl_resolvepath( 637 path_resolved_so_far, 638 presolvedsf, 639 &realpath_failed); 640 641 if (osl_File_E_None != ferr) 642 return ferr; 643 644 if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH)) 645 { 646 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 647 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 648 649 ustrchrcat(UNICHAR_SLASH, path_resolved_so_far); 650 } 651 } 652 } 653 else // any other character 654 { 655 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 656 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 657 658 ustrchrcat(*punresolved++, path_resolved_so_far); 659 660 if ('\0' == *punresolved && !realpath_failed) 661 { 662 ferr = _osl_resolvepath( 663 path_resolved_so_far, 664 presolvedsf, 665 &realpath_failed); 666 667 if (osl_File_E_None != ferr) 668 return ferr; 669 } 670 } 671 } 672 673 sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far); 674 675 OSL_ASSERT(len < PATH_MAX); 676 677 resolved_path = rtl::OUString(path_resolved_so_far, len); 678 679 return osl_File_E_None; 680 } 681 682 } // end namespace private 683 684 685 /****************************************************** 686 * osl_getAbsoluteFileURL 687 ******************************************************/ 688 689 oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL) 690 { 691 FileBase::RC rc; 692 rtl::OUString unresolved_path; 693 694 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path); 695 696 if(FileBase::E_None != rc) 697 return oslFileError(rc); 698 699 if (systemPathIsRelativePath(unresolved_path)) 700 { 701 rtl::OUString base_path; 702 rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False); 703 704 if (FileBase::E_None != rc) 705 return oslFileError(rc); 706 707 rtl::OUString abs_path; 708 systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path); 709 710 unresolved_path = abs_path; 711 } 712 713 rtl::OUString resolved_path; 714 rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path); 715 716 if (FileBase::E_None == rc) 717 { 718 rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL); 719 OSL_ASSERT(FileBase::E_None == rc); 720 } 721 722 return oslFileError(rc); 723 } 724 725 726 namespace /* private */ 727 { 728 729 /********************************************* 730 No separate error code if unicode to text 731 conversion or getenv fails because for the 732 caller there is no difference why a file 733 could not be found in $PATH 734 ********************************************/ 735 736 bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result) 737 { 738 bool bfound = false; 739 rtl::OUString path = rtl::OUString::createFromAscii("PATH"); 740 rtl::OUString env_path; 741 742 if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData)) 743 bfound = osl::searchPath(file_path, env_path, result); 744 745 return bfound; 746 } 747 748 /********************************************* 749 No separate error code if unicode to text 750 conversion or getcwd fails because for the 751 caller there is no difference why a file 752 could not be found in CDW 753 ********************************************/ 754 755 bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result) 756 { 757 bool bfound = false; 758 rtl::OUString cwd_url; 759 760 if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData)) 761 { 762 rtl::OUString cwd; 763 FileBase::getSystemPathFromFileURL(cwd_url, cwd); 764 bfound = osl::searchPath(file_path, cwd, result); 765 } 766 return bfound; 767 } 768 769 /********************************************* 770 771 ********************************************/ 772 773 bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result) 774 { 775 return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result)); 776 } 777 778 } // end namespace private 779 780 781 /**************************************************************************** 782 * osl_searchFileURL 783 ***************************************************************************/ 784 785 oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL) 786 { 787 OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter"); 788 789 FileBase::RC rc; 790 rtl::OUString file_path; 791 792 // try to interpret search path as file url else assume it's a system path list 793 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path); 794 if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc)) 795 file_path = ustrFilePath; 796 else if (FileBase::E_None != rc) 797 return oslFileError(rc); 798 799 bool bfound = false; 800 rtl::OUString result; 801 802 if (find_in_searchPath(file_path, ustrSearchPath, result) || 803 find_in_PATH(file_path, result) || 804 find_in_CWD(file_path, result)) 805 { 806 rtl::OUString resolved; 807 808 if (osl::realpath(result, resolved)) 809 { 810 #if OSL_DEBUG_LEVEL > 0 811 oslFileError osl_error = 812 #endif 813 osl_getFileURLFromSystemPath(resolved.pData, pustrURL); 814 OSL_ASSERT(osl_File_E_None == osl_error); 815 bfound = true; 816 } 817 } 818 return bfound ? osl_File_E_None : osl_File_E_NOENT; 819 } 820 821 822 /**************************************************************************** 823 * FileURLToPath 824 ***************************************************************************/ 825 826 oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL) 827 { 828 rtl_uString* ustrSystemPath = NULL; 829 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath); 830 831 if(osl_File_E_None != osl_error) 832 return osl_error; 833 834 osl_systemPathRemoveSeparator(ustrSystemPath); 835 836 /* convert unicode path to text */ 837 if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length)) 838 osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); 839 840 rtl_uString_release(ustrSystemPath); 841 842 return osl_error; 843 } 844 845 /***************************************************************************** 846 * UnicodeToText 847 ****************************************************************************/ 848 849 namespace /* private */ 850 { 851 class UnicodeToTextConverter_Impl 852 { 853 rtl_UnicodeToTextConverter m_converter; 854 855 UnicodeToTextConverter_Impl() 856 : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding())) 857 {} 858 859 ~UnicodeToTextConverter_Impl() 860 { 861 rtl_destroyUnicodeToTextConverter (m_converter); 862 } 863 public: 864 static UnicodeToTextConverter_Impl & getInstance() 865 { 866 static UnicodeToTextConverter_Impl g_theConverter; 867 return g_theConverter; 868 } 869 870 sal_Size convert( 871 sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes, 872 sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars) 873 { 874 OSL_ASSERT(m_converter != 0); 875 return rtl_convertUnicodeToText ( 876 m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars); 877 } 878 }; 879 } // end namespace private 880 881 int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen ) 882 { 883 sal_uInt32 nInfo = 0; 884 sal_Size nSrcChars = 0; 885 886 sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert ( 887 uniText, uniTextLen, buffer, bufLen, 888 OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars); 889 890 if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL ) 891 { 892 errno = EOVERFLOW; 893 return 0; 894 } 895 896 /* ensure trailing '\0' */ 897 buffer[nDestBytes] = '\0'; 898 return nDestBytes; 899 } 900 901 /***************************************************************************** 902 * TextToUnicode 903 ****************************************************************************/ 904 905 namespace /* private */ 906 { 907 class TextToUnicodeConverter_Impl 908 { 909 rtl_TextToUnicodeConverter m_converter; 910 911 TextToUnicodeConverter_Impl() 912 : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding())) 913 {} 914 915 ~TextToUnicodeConverter_Impl() 916 { 917 rtl_destroyTextToUnicodeConverter (m_converter); 918 } 919 920 public: 921 static TextToUnicodeConverter_Impl & getInstance() 922 { 923 static TextToUnicodeConverter_Impl g_theConverter; 924 return g_theConverter; 925 } 926 927 sal_Size convert( 928 sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars, 929 sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes) 930 { 931 OSL_ASSERT(m_converter != 0); 932 return rtl_convertTextToUnicode ( 933 m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes); 934 } 935 }; 936 } // end namespace private 937 938 int TextToUnicode( 939 const char* text, 940 size_t text_buffer_size, 941 sal_Unicode* unic_text, 942 sal_Int32 unic_text_buffer_size) 943 { 944 sal_uInt32 nInfo = 0; 945 sal_Size nSrcChars = 0; 946 947 sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert( 948 text, text_buffer_size, unic_text, unic_text_buffer_size, 949 OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars); 950 951 if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL) 952 { 953 errno = EOVERFLOW; 954 return 0; 955 } 956 957 /* ensure trailing '\0' */ 958 unic_text[nDestBytes] = '\0'; 959 return nDestBytes; 960 } 961