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: 212 303 70.0 %
Date: 2012-12-17 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      771967 : oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
     141             : {
     142             :     sal_Int32 nIndex;
     143      771967 :     rtl_uString * pTmp = NULL;
     144             : 
     145      771967 :     sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
     146      771967 :     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      771967 :     if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) )
     160             :     {
     161         418 :         return osl_File_E_INVAL;
     162             :     }
     163             : 
     164             :     /* Check for non file:// protocols */
     165             : 
     166      771549 :     nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 );
     167      771549 :     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      771549 :     nIndex = 0;
     175             : 
     176      771549 :     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      771549 :     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      771549 :     if( 7 <= pTmp->length )
     217             :     {
     218      771449 :         rtl_uString * pProtocol = NULL;
     219      771449 :         rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
     220             : 
     221             :         /* protocol is case insensitive */
     222      771449 :         rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
     223             : 
     224      771449 :         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
     225      771205 :             nIndex = 7;
     226             : 
     227      771449 :         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      771549 :     if( nIndex && ( 10 <= pTmp->length - nIndex ) )
     233             :     {
     234      746982 :         rtl_uString * pServer = NULL;
     235      746982 :         rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
     236             : 
     237             :         /* server is case insensitive */
     238      746982 :         rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
     239             : 
     240     1493964 :         if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
     241      746982 :             ( 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      746982 :         rtl_uString_release( pServer );
     248             :     }
     249             : 
     250      771549 :     if( nIndex )
     251      771205 :         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      771549 :     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      771549 :     *pustrSystemPath = pTmp;
     285      771549 :     return osl_File_E_None;
     286             : }
     287             : 
     288             : /****************************************************************************/
     289             : /*  osl_getFileURLFromSystemPath */
     290             : /****************************************************************************/
     291             : 
     292      153691 : oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
     293             : {
     294             :     static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
     295             : 
     296      153691 :     rtl_uString *pTmp = NULL;
     297             :     sal_Int32 nIndex;
     298             : 
     299      153691 :     if( 0 == ustrSystemPath->length )
     300          28 :         return osl_File_E_INVAL;
     301             : 
     302             :     /* temporary hack: if already file url, return ustrSystemPath */
     303             : 
     304      153663 :     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         284 :         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      153379 :     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      153379 :     nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
     353      153379 :     if( -1 != nIndex )
     354             :     {
     355             :         sal_Int32 nSrcIndex;
     356         130 :         sal_Int32 nDeleted = 0;
     357             : 
     358             :         /* if pTmp is not already allocated, copy ustrSystemPath for modification */
     359         130 :         if( NULL == pTmp )
     360         130 :             rtl_uString_newFromString( &pTmp, ustrSystemPath );
     361             : 
     362             :         /* adapt index to pTmp */
     363         130 :         nIndex += pTmp->length - ustrSystemPath->length;
     364             : 
     365             :         /* remove all occurrences of '//' */
     366        1926 :         for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
     367             :         {
     368        1796 :             if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) )
     369         130 :                 nDeleted++;
     370             :             else
     371        1666 :                 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
     372             :         }
     373             : 
     374             :         /* adjust length member */
     375         130 :         pTmp->length -= nDeleted;
     376             :     }
     377             : 
     378      153379 :     if( NULL == pTmp )
     379      153249 :         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      153379 :     rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
     388             : 
     389      153379 :     rtl_uString_release( pTmp );
     390             : 
     391             :     /* absolute urls should start with 'file://' */
     392      153379 :     if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] )
     393             :     {
     394      153041 :         rtl_uString *pProtocol = NULL;
     395             : 
     396      153041 :         rtl_uString_newFromAscii( &pProtocol, "file://" );
     397      153041 :         rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
     398      153041 :         rtl_uString_release( pProtocol );
     399             :     }
     400             : 
     401      153379 :     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      580499 : oslFileError osl_getSystemPathFromFileURL_Ex(
     411             :     rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative)
     412             : {
     413      580499 :     rtl_uString* temp = 0;
     414      580499 :     oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
     415             : 
     416      580499 :     if (osl_File_E_None == osl_error)
     417             :     {
     418      580377 :         if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0]))
     419             :         {
     420      580375 :             *pustrSystemPath = temp;
     421             :         }
     422             :         else
     423             :         {
     424           2 :             rtl_uString_release(temp);
     425           2 :             osl_error = osl_File_E_INVAL;
     426             :         }
     427             :     }
     428             : 
     429      580499 :     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     2407772 :     sal_Unicode* ustrtoend(sal_Unicode* pStr)
     441             :     {
     442     2407772 :         return (pStr + rtl_ustr_getLength(pStr));
     443             :     }
     444             : 
     445             :     /*********************************************
     446             : 
     447             :      ********************************************/
     448             : 
     449     1139721 :     sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
     450             :     {
     451     1139721 :         sal_Unicode* p = ustrtoend(d);
     452     1139721 :         *p++ = chr;
     453     1139721 :         *p   = 0;
     454     1139721 :         return d;
     455             :     }
     456             : 
     457             :     /******************************************************
     458             :      *
     459             :      ******************************************************/
     460             : 
     461      127116 :     bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
     462             :     {
     463      127116 :            sal_Unicode* p = ustrtoend(pStr);
     464      127116 :            if (p > pStr)
     465      127116 :                p--;
     466      127116 :            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         607 :     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         607 :         sal_Unicode* p = ustrtoend(aPath) - 2;
     484             : 
     485             :         // move back to the next path separator
     486             :         // or to the start of the string
     487        3587 :         while ((p > aPath) && (*p != UNICHAR_SLASH))
     488        2373 :             p--;
     489             : 
     490         607 :         if (p >= aPath)
     491             :         {
     492         607 :             if (UNICHAR_SLASH == *p)
     493             :             {
     494         607 :                 p++;
     495         607 :                *p = '\0';
     496             :             }
     497             :             else
     498             :             {
     499           0 :                    *p = '\0';
     500             :             }
     501             :         }
     502             : 
     503         607 :         return aPath;
     504             :     }
     505             : 
     506             :     /******************************************************
     507             :      *
     508             :      ******************************************************/
     509             : 
     510      142477 :     oslFileError _osl_resolvepath(
     511             :         /*inout*/ sal_Unicode* path,
     512             :         /*inout*/ bool* failed)
     513             :     {
     514      142477 :         oslFileError ferr = osl_File_E_None;
     515             : 
     516      142477 :         if (!*failed)
     517             :         {
     518             :             char unresolved_path[PATH_MAX];
     519      142477 :             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      142477 :             if (realpath(unresolved_path, resolved_path))
     524             :             {
     525      142369 :                 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
     526           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     527             : 
     528             :             }
     529             :             else
     530             :             {
     531         108 :                 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
     532         108 :                     *failed = true;
     533             :                 else
     534           0 :                     ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
     535             :             }
     536             :         }
     537             : 
     538      142477 :         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       15419 :     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       15419 :         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       15419 :         const sal_Unicode* punresolved = unresolved_path.getStr();
     555       15419 :         sal_Unicode*       presolvedsf = path_resolved_so_far;
     556             : 
     557             :         // reserve space for leading '/' and trailing '\0'
     558             :         // do not exceed this limit
     559       15419 :         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       15419 :         bool realpath_failed = false;
     565             :         oslFileError ferr;
     566             : 
     567       15419 :         path_resolved_so_far[0] = '\0';
     568             : 
     569     1059515 :         while (*punresolved != '\0')
     570             :         {
     571             :             // ignore '/.' , skip one part back when '/..'
     572             : 
     573     1028677 :             if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf))
     574             :             {
     575         611 :                 if ('\0' == *(punresolved + 1))
     576             :                 {
     577           0 :                     punresolved++;
     578           0 :                     continue;
     579             :                 }
     580         611 :                 else if (UNICHAR_SLASH == *(punresolved + 1))
     581             :                 {
     582           4 :                     punresolved += 2;
     583           4 :                     continue;
     584             :                 }
     585         607 :                 else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2))))
     586             :                 {
     587         607 :                     _rmlastpathtoken(path_resolved_so_far);
     588             : 
     589         607 :                     presolvedsf = ustrtoend(path_resolved_so_far) - 1;
     590             : 
     591         607 :                     if (UNICHAR_SLASH == *(punresolved + 2))
     592         583 :                         punresolved += 3;
     593             :                     else
     594          24 :                         punresolved += 2;
     595             : 
     596         607 :                     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     1028066 :             else if (UNICHAR_SLASH == *punresolved)
     617             :             {
     618      127166 :                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     619           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     620             : 
     621      127166 :                 ustrchrcat(*punresolved++, path_resolved_so_far);
     622             : 
     623      127166 :                 if (!realpath_failed)
     624             :                 {
     625             :                     ferr = _osl_resolvepath(
     626             :                         path_resolved_so_far,
     627      127116 :                         &realpath_failed);
     628             : 
     629      127116 :                     if (osl_File_E_None != ferr)
     630           0 :                         return ferr;
     631             : 
     632      127116 :                     if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH))
     633             :                     {
     634      111655 :                         if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     635           0 :                             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     636             : 
     637      111655 :                         ustrchrcat(UNICHAR_SLASH, path_resolved_so_far);
     638             :                     }
     639             :                 }
     640             :             }
     641             :             else // any other character
     642             :             {
     643      900900 :                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     644           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     645             : 
     646      900900 :                 ustrchrcat(*punresolved++, path_resolved_so_far);
     647             : 
     648      900900 :                 if ('\0' == *punresolved && !realpath_failed)
     649             :                 {
     650             :                     ferr = _osl_resolvepath(
     651             :                         path_resolved_so_far,
     652       15361 :                         &realpath_failed);
     653             : 
     654       15361 :                     if (osl_File_E_None != ferr)
     655           0 :                         return ferr;
     656             :                 }
     657             :             }
     658             :         }
     659             : 
     660       15419 :         sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
     661             : 
     662             :         OSL_ASSERT(len < PATH_MAX);
     663             : 
     664       15419 :         resolved_path = rtl::OUString(path_resolved_so_far, len);
     665             : 
     666       15419 :         return osl_File_E_None;
     667             :     }
     668             : 
     669             : } // end namespace private
     670             : 
     671             : 
     672             : /******************************************************
     673             :  * osl_getAbsoluteFileURL
     674             :  ******************************************************/
     675             : 
     676       15427 : oslFileError osl_getAbsoluteFileURL(rtl_uString*  ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
     677             : {
     678             :     FileBase::RC  rc;
     679       15427 :     rtl::OUString unresolved_path;
     680             : 
     681       15427 :     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path);
     682             : 
     683       15427 :     if(FileBase::E_None != rc)
     684           8 :         return oslFileError(rc);
     685             : 
     686       15419 :     if (systemPathIsRelativePath(unresolved_path))
     687             :     {
     688          58 :         rtl::OUString base_path;
     689          58 :         rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False);
     690             : 
     691          58 :         if (FileBase::E_None != rc)
     692           0 :             return oslFileError(rc);
     693             : 
     694          58 :         rtl::OUString abs_path;
     695          58 :         systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
     696             : 
     697          58 :         unresolved_path = abs_path;
     698             :     }
     699             : 
     700       15419 :     rtl::OUString resolved_path;
     701             : 
     702       15419 :     static bool allow_symlinks = getenv("SAL_ALLOW_LINKOO_SYMLINKS") != 0;
     703             :         // getenv is not thread safe, so minimize use of result
     704       15419 :     if (!allow_symlinks)
     705             :     {
     706       14762 :         rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
     707             :     }
     708             :     else
     709             :     {
     710             :         // SAL_ALLOW_LINKOO_SYMLINKS environment variable:
     711             :         // for linkoo to work, we need to let the symlinks to the libraries untouched
     712         657 :         rtl::OUString base;
     713         657 :         sal_Int32 last_slash = unresolved_path.lastIndexOf( UNICHAR_SLASH );
     714             : 
     715        2612 :         if (last_slash >= 0 && last_slash + 1 < unresolved_path.getLength()
     716         657 :             && ! ( last_slash + 2 == unresolved_path.getLength() && unresolved_path.matchAsciiL(RTL_CONSTASCII_STRINGPARAM("."), last_slash + 1) )
     717         673 :             && ! ( last_slash + 3 == unresolved_path.getLength() && unresolved_path.matchAsciiL(RTL_CONSTASCII_STRINGPARAM(".."), last_slash + 1) ))
     718             :         {
     719         641 :             base = unresolved_path.copy(last_slash+1);
     720         641 :             unresolved_path = unresolved_path.copy(0, last_slash);
     721             :         }
     722             : 
     723         657 :         rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
     724             : 
     725         657 :         if (!base.isEmpty())
     726             :         {
     727         641 :             resolved_path += rtl::OUString( UNICHAR_SLASH );
     728         641 :             resolved_path += base;
     729         657 :         }
     730             :     }
     731             : 
     732       15419 :     if (FileBase::E_None == rc)
     733             :     {
     734       15419 :         rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
     735             :         OSL_ASSERT(FileBase::E_None == rc);
     736             :     }
     737             : 
     738       15419 :     return oslFileError(rc);
     739             : }
     740             : 
     741             : 
     742             : namespace /* private */
     743             : {
     744             : 
     745             :     /*********************************************
     746             :      No separate error code if unicode to text
     747             :      conversion or getenv fails because for the
     748             :      caller there is no difference why a file
     749             :      could not be found in $PATH
     750             :      ********************************************/
     751             : 
     752           0 :     bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
     753             :     {
     754           0 :         bool          bfound = false;
     755           0 :         rtl::OUString path(RTL_CONSTASCII_USTRINGPARAM("PATH"));
     756           0 :         rtl::OUString env_path;
     757             : 
     758           0 :         if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
     759           0 :             bfound = osl::searchPath(file_path, env_path, result);
     760             : 
     761           0 :         return bfound;
     762             :     }
     763             : 
     764             :     /*********************************************
     765             :      No separate error code if unicode to text
     766             :      conversion or getcwd fails because for the
     767             :      caller there is no difference why a file
     768             :      could not be found in CDW
     769             :      ********************************************/
     770             : 
     771           0 :     bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
     772             :     {
     773           0 :         bool bfound = false;
     774           0 :         rtl::OUString cwd_url;
     775             : 
     776           0 :         if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
     777             :         {
     778           0 :             rtl::OUString cwd;
     779           0 :             FileBase::getSystemPathFromFileURL(cwd_url, cwd);
     780           0 :             bfound = osl::searchPath(file_path, cwd, result);
     781             :         }
     782           0 :         return bfound;
     783             :     }
     784             : 
     785             :     /*********************************************
     786             : 
     787             :      ********************************************/
     788             : 
     789           0 :     bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
     790             :     {
     791           0 :         return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
     792             :     }
     793             : 
     794             : } // end namespace private
     795             : 
     796             : 
     797             : /****************************************************************************
     798             :  *  osl_searchFileURL
     799             :  ***************************************************************************/
     800             : 
     801           0 : oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
     802             : {
     803             :     OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
     804             : 
     805             :     FileBase::RC  rc;
     806           0 :     rtl::OUString file_path;
     807             : 
     808             :     // try to interpret search path as file url else assume it's a system path list
     809           0 :     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
     810           0 :     if (FileBase::E_INVAL == rc)
     811           0 :         file_path = ustrFilePath;
     812           0 :     else if (FileBase::E_None != rc)
     813           0 :         return oslFileError(rc);
     814             : 
     815           0 :     bool          bfound = false;
     816           0 :     rtl::OUString result;
     817             : 
     818           0 :     if (find_in_searchPath(file_path, ustrSearchPath, result) ||
     819           0 :         find_in_PATH(file_path, result) ||
     820           0 :         find_in_CWD(file_path, result))
     821             :     {
     822           0 :         rtl::OUString resolved;
     823             : 
     824           0 :         if (osl::realpath(result, resolved))
     825             :         {
     826             : #if OSL_DEBUG_LEVEL > 0
     827             :             oslFileError osl_error =
     828             : #endif
     829           0 :                 osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
     830             :             OSL_ASSERT(osl_File_E_None == osl_error);
     831           0 :             bfound = true;
     832           0 :         }
     833             :     }
     834           0 :     return bfound ? osl_File_E_None : osl_File_E_NOENT;
     835             : }
     836             : 
     837             : 
     838             : /****************************************************************************
     839             :  * FileURLToPath
     840             :  ***************************************************************************/
     841             : 
     842       48845 : oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
     843             : {
     844       48845 :     rtl_uString* ustrSystemPath = NULL;
     845       48845 :     oslFileError osl_error      = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
     846             : 
     847       48845 :     if(osl_File_E_None != osl_error)
     848          10 :         return osl_error;
     849             : 
     850       48835 :     osl_systemPathRemoveSeparator(ustrSystemPath);
     851             : 
     852             :     /* convert unicode path to text */
     853       48835 :     if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
     854           0 :         osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
     855             : 
     856       48835 :     rtl_uString_release(ustrSystemPath);
     857             : 
     858       48835 :     return osl_error;
     859             : }
     860             : 
     861             : /*****************************************************************************
     862             :  * UnicodeToText
     863             :  ****************************************************************************/
     864             : 
     865             : namespace /* private */
     866             : {
     867             :     class UnicodeToTextConverter_Impl
     868             :     {
     869             :         rtl_UnicodeToTextConverter m_converter;
     870             : 
     871         399 :         UnicodeToTextConverter_Impl()
     872         399 :             : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
     873         399 :         {}
     874             : 
     875         399 :         ~UnicodeToTextConverter_Impl()
     876             :         {
     877         399 :             rtl_destroyUnicodeToTextConverter (m_converter);
     878         399 :         }
     879             :     public:
     880      236469 :         static UnicodeToTextConverter_Impl & getInstance()
     881             :         {
     882      236469 :             static UnicodeToTextConverter_Impl g_theConverter;
     883      236469 :             return g_theConverter;
     884             :         }
     885             : 
     886      236469 :         sal_Size convert(
     887             :             sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes,
     888             :             sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars)
     889             :         {
     890             :             OSL_ASSERT(m_converter != 0);
     891             :             return rtl_convertUnicodeToText (
     892      236469 :                 m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars);
     893             :         }
     894             :     };
     895             : } // end namespace private
     896             : 
     897      236469 : int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
     898             : {
     899      236469 :     sal_uInt32   nInfo = 0;
     900      236469 :     sal_Size     nSrcChars = 0;
     901             : 
     902      236469 :     sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert (
     903             :         uniText, uniTextLen, buffer, bufLen,
     904      472938 :         OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars);
     905             : 
     906      236469 :     if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
     907             :     {
     908           0 :         errno = EOVERFLOW;
     909           0 :         return 0;
     910             :     }
     911             : 
     912             :     /* ensure trailing '\0' */
     913      236469 :     buffer[nDestBytes] = '\0';
     914      236469 :     return nDestBytes;
     915             : }
     916             : 
     917             : /*****************************************************************************
     918             :  * TextToUnicode
     919             :  ****************************************************************************/
     920             : 
     921             : namespace /* private */
     922             : {
     923             :     class TextToUnicodeConverter_Impl
     924             :     {
     925             :         rtl_TextToUnicodeConverter m_converter;
     926             : 
     927         391 :         TextToUnicodeConverter_Impl()
     928         391 :             : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
     929         391 :         {}
     930             : 
     931         391 :         ~TextToUnicodeConverter_Impl()
     932             :         {
     933         391 :             rtl_destroyTextToUnicodeConverter (m_converter);
     934         391 :         }
     935             : 
     936             :     public:
     937      142369 :         static TextToUnicodeConverter_Impl & getInstance()
     938             :         {
     939      142369 :             static TextToUnicodeConverter_Impl g_theConverter;
     940      142369 :             return g_theConverter;
     941             :         }
     942             : 
     943      142369 :         sal_Size convert(
     944             :             sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars,
     945             :             sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes)
     946             :         {
     947             :             OSL_ASSERT(m_converter != 0);
     948             :             return rtl_convertTextToUnicode (
     949      142369 :                 m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes);
     950             :         }
     951             :     };
     952             : } // end namespace private
     953             : 
     954      142369 : int TextToUnicode(
     955             :     const char*  text,
     956             :     size_t       text_buffer_size,
     957             :     sal_Unicode* unic_text,
     958             :     sal_Int32    unic_text_buffer_size)
     959             : {
     960      142369 :     sal_uInt32 nInfo = 0;
     961      142369 :     sal_Size   nSrcChars = 0;
     962             : 
     963      142369 :     sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert(
     964             :         text,  text_buffer_size, unic_text, unic_text_buffer_size,
     965      284738 :         OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars);
     966             : 
     967      142369 :     if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
     968             :     {
     969           0 :         errno = EOVERFLOW;
     970           0 :         return 0;
     971             :     }
     972             : 
     973             :     /* ensure trailing '\0' */
     974      142369 :     unic_text[nDestBytes] = '\0';
     975      142369 :     return nDestBytes;
     976             : }
     977             : 
     978             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10