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