LCOV - code coverage report
Current view: top level - libreoffice/sal/osl/unx - file_url.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 202 308 65.6 %
Date: 2012-12-27 Functions: 21 26 80.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10