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 '/' devided 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 267 /* osl_getHomeDir returns file URL */ 268 osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 ); 269 270 /* remove "file://" prefix */ 271 rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 ); 272 273 /* replace '~' in original string */ 274 rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 ); 275 rtl_uString_release( pTmp2 ); 276 } 277 278 else 279 { 280 /* FIXME: replace ~user with users home directory */ 281 return osl_File_E_INVAL; 282 } 283 } 284 285 /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ 286 /* 287 OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); 288 */ 289 290 *pustrSystemPath = pTmp; 291 return osl_File_E_None; 292 } 293 294 /****************************************************************************/ 295 /* osl_getFileURLFromSystemPath */ 296 /****************************************************************************/ 297 298 oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL ) 299 { 300 static const sal_Unicode pDoubleSlash[2] = { '/', '/' }; 301 302 rtl_uString *pTmp = NULL; 303 sal_Int32 nIndex; 304 305 if( 0 == ustrSystemPath->length ) 306 return osl_File_E_INVAL; 307 308 /* temporary hack: if already file url, return ustrSystemPath */ 309 310 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) ) 311 { 312 /* 313 if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) ) 314 { 315 OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" ); 316 rtl_uString_assign( pustrFileURL, ustrSystemPath ); 317 } 318 else 319 { 320 rtl_uString *pTmp2 = NULL; 321 322 OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" ); 323 rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 ); 324 rtl_uString_newFromAscii( &pTmp2, "file://" ); 325 rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 ); 326 rtl_uString_release( pTmp2 ); 327 } 328 return osl_File_E_None; 329 */ 330 return osl_File_E_INVAL; 331 } 332 333 334 /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */ 335 if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] ) 336 { 337 /* check if another user is specified */ 338 if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) ) 339 { 340 /* osl_getHomeDir returns file URL */ 341 osl_getHomeDir( osl_getCurrentSecurity(), &pTmp ); 342 343 /* remove "file://" prefix */ 344 rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 ); 345 346 /* replace '~' in original string */ 347 rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp ); 348 } 349 350 else 351 { 352 /* FIXME: replace ~user with users home directory */ 353 return osl_File_E_INVAL; 354 } 355 } 356 357 /* check if initial string contains double instances of '/' */ 358 nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 ); 359 if( -1 != nIndex ) 360 { 361 sal_Int32 nSrcIndex; 362 sal_Int32 nDeleted = 0; 363 364 /* if pTmp is not already allocated, copy ustrSystemPath for modification */ 365 if( NULL == pTmp ) 366 rtl_uString_newFromString( &pTmp, ustrSystemPath ); 367 368 /* adapt index to pTmp */ 369 nIndex += pTmp->length - ustrSystemPath->length; 370 371 /* remove all occurances of '//' */ 372 for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ ) 373 { 374 if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) ) 375 nDeleted++; 376 else 377 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex]; 378 } 379 380 /* adjust length member */ 381 pTmp->length -= nDeleted; 382 } 383 384 if( NULL == pTmp ) 385 rtl_uString_assign( &pTmp, ustrSystemPath ); 386 387 /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */ 388 /* 389 OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) ); 390 */ 391 392 /* file URLs must be URI encoded */ 393 rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL ); 394 395 rtl_uString_release( pTmp ); 396 397 /* absolute urls should start with 'file://' */ 398 if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] ) 399 { 400 rtl_uString *pProtocol = NULL; 401 402 rtl_uString_newFromAscii( &pProtocol, "file://" ); 403 rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL ); 404 rtl_uString_release( pProtocol ); 405 } 406 407 return osl_File_E_None; 408 } 409 410 /**************************************************************************** 411 * osl_getSystemPathFromFileURL_Ex - helper function 412 * clients may specify if they want to accept relative 413 * URLs or not 414 ****************************************************************************/ 415 416 oslFileError osl_getSystemPathFromFileURL_Ex( 417 rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative) 418 { 419 rtl_uString* temp = 0; 420 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp); 421 422 if (osl_File_E_None == osl_error) 423 { 424 if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0])) 425 { 426 *pustrSystemPath = temp; 427 } 428 else 429 { 430 rtl_uString_release(temp); 431 osl_error = osl_File_E_INVAL; 432 } 433 } 434 435 return osl_error; 436 } 437 438 namespace /* private */ 439 { 440 441 /****************************************************** 442 * Helper function, return a pinter to the final '\0' 443 * of a string 444 ******************************************************/ 445 446 sal_Unicode* ustrtoend(sal_Unicode* pStr) 447 { 448 return (pStr + rtl_ustr_getLength(pStr)); 449 } 450 451 /********************************************* 452 453 ********************************************/ 454 455 sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d) 456 { 457 sal_Unicode* p = ustrtoend(d); 458 *p++ = chr; 459 *p = 0; 460 return d; 461 } 462 463 /****************************************************** 464 * 465 ******************************************************/ 466 467 bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr) 468 { 469 sal_Unicode* p = ustrtoend(pStr); 470 if (p > pStr) 471 p--; 472 return (*p == Chr); 473 } 474 475 /****************************************************** 476 * Remove the last part of a path, a path that has 477 * only a '/' or no '/' at all will be returned 478 * unmodified 479 ******************************************************/ 480 481 sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath) 482 { 483 /* we always may skip -2 because we 484 may at least stand on a '/' but 485 either there is no other character 486 before this '/' or it's another 487 character than the '/' 488 */ 489 sal_Unicode* p = ustrtoend(aPath) - 2; 490 491 // move back to the next path separator 492 // or to the start of the string 493 while ((p > aPath) && (*p != UNICHAR_SLASH)) 494 p--; 495 496 if (p >= aPath) 497 { 498 if (UNICHAR_SLASH == *p) 499 { 500 p++; 501 *p = '\0'; 502 } 503 else 504 { 505 *p = '\0'; 506 } 507 } 508 509 return aPath; 510 } 511 512 /****************************************************** 513 * 514 ******************************************************/ 515 516 oslFileError _osl_resolvepath( 517 /*inout*/ sal_Unicode* path, 518 /*inout*/ sal_Unicode* current_pos, 519 /*inout*/ bool* failed) 520 { 521 oslFileError ferr = osl_File_E_None; 522 523 if (!*failed) 524 { 525 char unresolved_path[PATH_MAX]; 526 if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path))) 527 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 528 529 char resolved_path[PATH_MAX]; 530 if (realpath(unresolved_path, resolved_path)) 531 { 532 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX)) 533 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 534 535 current_pos = ustrtoend(path) - 1; 536 } 537 else 538 { 539 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno) 540 *failed = true; 541 else 542 ferr = oslTranslateFileError(OSL_FET_ERROR, errno); 543 } 544 } 545 546 return ferr; 547 } 548 549 /****************************************************** 550 * Works even with non existing paths. The resulting 551 * path must not exceed PATH_MAX else 552 * osl_File_E_NAMETOOLONG is the result 553 ******************************************************/ 554 555 oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path) 556 { 557 // the given unresolved path must not exceed PATH_MAX 558 if (unresolved_path.getLength() >= (PATH_MAX - 2)) 559 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 560 561 sal_Unicode path_resolved_so_far[PATH_MAX]; 562 const sal_Unicode* punresolved = unresolved_path.getStr(); 563 sal_Unicode* presolvedsf = path_resolved_so_far; 564 565 // reserve space for leading '/' and trailing '\0' 566 // do not exceed this limit 567 sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2; 568 569 // if realpath fails with error ENOTDIR, EACCES or ENOENT 570 // we will not call it again, because _osl_realpath should also 571 // work with non existing directories etc. 572 bool realpath_failed = false; 573 oslFileError ferr; 574 575 path_resolved_so_far[0] = '\0'; 576 577 while (*punresolved != '\0') 578 { 579 // ignore '/.' , skip one part back when '/..' 580 581 if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf)) 582 { 583 if ('\0' == *(punresolved + 1)) 584 { 585 punresolved++; 586 continue; 587 } 588 else if (UNICHAR_SLASH == *(punresolved + 1)) 589 { 590 punresolved += 2; 591 continue; 592 } 593 else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2)))) 594 { 595 _rmlastpathtoken(path_resolved_so_far); 596 597 presolvedsf = ustrtoend(path_resolved_so_far) - 1; 598 599 if (UNICHAR_SLASH == *(punresolved + 2)) 600 punresolved += 3; 601 else 602 punresolved += 2; 603 604 continue; 605 } 606 else // a file or directory name may start with '.' 607 { 608 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 609 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 610 611 ustrchrcat(*punresolved++, path_resolved_so_far); 612 613 if ('\0' == *punresolved && !realpath_failed) 614 { 615 ferr = _osl_resolvepath( 616 path_resolved_so_far, 617 presolvedsf, 618 &realpath_failed); 619 620 if (osl_File_E_None != ferr) 621 return ferr; 622 } 623 } 624 } 625 else if (UNICHAR_SLASH == *punresolved) 626 { 627 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 628 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 629 630 ustrchrcat(*punresolved++, path_resolved_so_far); 631 632 if (!realpath_failed) 633 { 634 ferr = _osl_resolvepath( 635 path_resolved_so_far, 636 presolvedsf, 637 &realpath_failed); 638 639 if (osl_File_E_None != ferr) 640 return ferr; 641 642 if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH)) 643 { 644 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 645 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 646 647 ustrchrcat(UNICHAR_SLASH, path_resolved_so_far); 648 } 649 } 650 } 651 else // any other character 652 { 653 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel) 654 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG); 655 656 ustrchrcat(*punresolved++, path_resolved_so_far); 657 658 if ('\0' == *punresolved && !realpath_failed) 659 { 660 ferr = _osl_resolvepath( 661 path_resolved_so_far, 662 presolvedsf, 663 &realpath_failed); 664 665 if (osl_File_E_None != ferr) 666 return ferr; 667 } 668 } 669 } 670 671 sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far); 672 673 OSL_ASSERT(len < PATH_MAX); 674 675 resolved_path = rtl::OUString(path_resolved_so_far, len); 676 677 return osl_File_E_None; 678 } 679 680 } // end namespace private 681 682 683 /****************************************************** 684 * osl_getAbsoluteFileURL 685 ******************************************************/ 686 687 oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL) 688 { 689 FileBase::RC rc; 690 rtl::OUString unresolved_path; 691 692 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path); 693 694 if(FileBase::E_None != rc) 695 return oslFileError(rc); 696 697 if (systemPathIsRelativePath(unresolved_path)) 698 { 699 rtl::OUString base_path; 700 rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False); 701 702 if (FileBase::E_None != rc) 703 return oslFileError(rc); 704 705 rtl::OUString abs_path; 706 systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path); 707 708 unresolved_path = abs_path; 709 } 710 711 rtl::OUString resolved_path; 712 rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path); 713 714 if (FileBase::E_None == rc) 715 { 716 rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL); 717 OSL_ASSERT(FileBase::E_None == rc); 718 } 719 720 return oslFileError(rc); 721 } 722 723 724 namespace /* private */ 725 { 726 727 /********************************************* 728 No separate error code if unicode to text 729 conversion or getenv fails because for the 730 caller there is no difference why a file 731 could not be found in $PATH 732 ********************************************/ 733 734 bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result) 735 { 736 bool bfound = false; 737 rtl::OUString path = rtl::OUString::createFromAscii("PATH"); 738 rtl::OUString env_path; 739 740 if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData)) 741 bfound = osl::searchPath(file_path, env_path, result); 742 743 return bfound; 744 } 745 746 /********************************************* 747 No separate error code if unicode to text 748 conversion or getcwd fails because for the 749 caller there is no difference why a file 750 could not be found in CDW 751 ********************************************/ 752 753 bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result) 754 { 755 bool bfound = false; 756 rtl::OUString cwd_url; 757 758 if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData)) 759 { 760 rtl::OUString cwd; 761 FileBase::getSystemPathFromFileURL(cwd_url, cwd); 762 bfound = osl::searchPath(file_path, cwd, result); 763 } 764 return bfound; 765 } 766 767 /********************************************* 768 769 ********************************************/ 770 771 bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result) 772 { 773 return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result)); 774 } 775 776 } // end namespace private 777 778 779 /**************************************************************************** 780 * osl_searchFileURL 781 ***************************************************************************/ 782 783 oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL) 784 { 785 OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter"); 786 787 FileBase::RC rc; 788 rtl::OUString file_path; 789 790 // try to interpret search path as file url else assume it's a system path list 791 rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path); 792 if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc)) 793 file_path = ustrFilePath; 794 else if (FileBase::E_None != rc) 795 return oslFileError(rc); 796 797 bool bfound = false; 798 rtl::OUString result; 799 800 if (find_in_searchPath(file_path, ustrSearchPath, result) || 801 find_in_PATH(file_path, result) || 802 find_in_CWD(file_path, result)) 803 { 804 rtl::OUString resolved; 805 806 if (osl::realpath(result, resolved)) 807 { 808 #if OSL_DEBUG_LEVEL > 0 809 oslFileError osl_error = 810 #endif 811 osl_getFileURLFromSystemPath(resolved.pData, pustrURL); 812 OSL_ASSERT(osl_File_E_None == osl_error); 813 bfound = true; 814 } 815 } 816 return bfound ? osl_File_E_None : osl_File_E_NOENT; 817 } 818 819 820 /**************************************************************************** 821 * FileURLToPath 822 ***************************************************************************/ 823 824 oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL) 825 { 826 rtl_uString* ustrSystemPath = NULL; 827 oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath); 828 829 if(osl_File_E_None != osl_error) 830 return osl_error; 831 832 osl_systemPathRemoveSeparator(ustrSystemPath); 833 834 /* convert unicode path to text */ 835 if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length)) 836 osl_error = oslTranslateFileError(OSL_FET_ERROR, errno); 837 838 rtl_uString_release(ustrSystemPath); 839 840 return osl_error; 841 } 842 843 /***************************************************************************** 844 * UnicodeToText 845 ****************************************************************************/ 846 847 namespace /* private */ 848 { 849 class UnicodeToTextConverter_Impl 850 { 851 rtl_UnicodeToTextConverter m_converter; 852 853 UnicodeToTextConverter_Impl() 854 : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding())) 855 {} 856 857 ~UnicodeToTextConverter_Impl() 858 { 859 rtl_destroyUnicodeToTextConverter (m_converter); 860 } 861 public: 862 static UnicodeToTextConverter_Impl & getInstance() 863 { 864 static UnicodeToTextConverter_Impl g_theConverter; 865 return g_theConverter; 866 } 867 868 sal_Size convert( 869 sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes, 870 sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars) 871 { 872 OSL_ASSERT(m_converter != 0); 873 return rtl_convertUnicodeToText ( 874 m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars); 875 } 876 }; 877 } // end namespace private 878 879 int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen ) 880 { 881 sal_uInt32 nInfo = 0; 882 sal_Size nSrcChars = 0; 883 884 sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert ( 885 uniText, uniTextLen, buffer, bufLen, 886 OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars); 887 888 if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL ) 889 { 890 errno = EOVERFLOW; 891 return 0; 892 } 893 894 /* ensure trailing '\0' */ 895 buffer[nDestBytes] = '\0'; 896 return nDestBytes; 897 } 898 899 /***************************************************************************** 900 * TextToUnicode 901 ****************************************************************************/ 902 903 namespace /* private */ 904 { 905 class TextToUnicodeConverter_Impl 906 { 907 rtl_TextToUnicodeConverter m_converter; 908 909 TextToUnicodeConverter_Impl() 910 : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding())) 911 {} 912 913 ~TextToUnicodeConverter_Impl() 914 { 915 rtl_destroyTextToUnicodeConverter (m_converter); 916 } 917 918 public: 919 static TextToUnicodeConverter_Impl & getInstance() 920 { 921 static TextToUnicodeConverter_Impl g_theConverter; 922 return g_theConverter; 923 } 924 925 sal_Size convert( 926 sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars, 927 sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes) 928 { 929 OSL_ASSERT(m_converter != 0); 930 return rtl_convertTextToUnicode ( 931 m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes); 932 } 933 }; 934 } // end namespace private 935 936 int TextToUnicode( 937 const char* text, 938 size_t text_buffer_size, 939 sal_Unicode* unic_text, 940 sal_Int32 unic_text_buffer_size) 941 { 942 sal_uInt32 nInfo = 0; 943 sal_Size nSrcChars = 0; 944 945 sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert( 946 text, text_buffer_size, unic_text, unic_text_buffer_size, 947 OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars); 948 949 if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL) 950 { 951 errno = EOVERFLOW; 952 return 0; 953 } 954 955 /* ensure trailing '\0' */ 956 unic_text[nDestBytes] = '\0'; 957 return nDestBytes; 958 } 959