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