LCOV - code coverage report
Current view: top level - sal/osl/unx - file_url.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 228 299 76.3 %
Date: 2015-06-13 12:38:46 Functions: 24 26 92.3 %
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             : #include "file_url.hxx"
      21             : 
      22             : #include "system.hxx"
      23             : 
      24             : #include <limits.h>
      25             : #include <errno.h>
      26             : #include <strings.h>
      27             : #include <unistd.h>
      28             : 
      29             : #include "osl/file.hxx"
      30             : #include <osl/security.h>
      31             : #include <osl/diagnose.h>
      32             : #include <osl/thread.h>
      33             : #include <osl/process.h>
      34             : 
      35             : #include <rtl/uri.h>
      36             : #include <rtl/ustring.hxx>
      37             : #include <rtl/ustrbuf.h>
      38             : #include "rtl/textcvt.h"
      39             : 
      40             : #include "file_error_transl.hxx"
      41             : #include "file_path_helper.hxx"
      42             : 
      43             : #include "uunxapi.hxx"
      44             : 
      45             : /***************************************************
      46             : 
      47             :  General note
      48             : 
      49             :  This file contains the part that handles File URLs.
      50             : 
      51             :  File URLs as scheme specific notion of URIs
      52             :  (RFC2396) may be handled platform independent, but
      53             :  will not in osl which is considered wrong.
      54             :  Future version of osl should handle File URLs this
      55             :  way. In rtl/uri there is already an URI parser etc.
      56             :  so this code should be consolidated.
      57             : 
      58             :  **************************************************/
      59             : 
      60             : using namespace osl;
      61             : 
      62             : /* a slightly modified version of Pchar in rtl/source/uri.c */
      63             : const sal_Bool uriCharClass[128] =
      64             : {
      65             :   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */
      66             :   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      67             :   0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./  */
      68             :   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */
      69             :   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */
      70             :   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */
      71             :   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */
      72             :   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0  /* pqrstuvwxyz{|}~  */
      73             : };
      74             : 
      75           0 : oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL )
      76             : {
      77             :     OSL_FAIL("osl_getCanonicalName not implemented");
      78             : 
      79           0 :     rtl_uString_newFromString(pustrValidURL, ustrFileURL);
      80           0 :     return osl_File_E_None;
      81             : }
      82             : 
      83     1074703 : oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
      84             : {
      85             :     sal_Int32 nIndex;
      86     1074703 :     rtl_uString * pTmp = NULL;
      87             : 
      88     1074703 :     sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
      89     1074703 :     sal_Unicode protocolDelimiter[3] = { ':', '/', '/' };
      90             : 
      91             :     /* a valid file url may not start with '/' */
      92     1074703 :     if( ( 0 == ustrFileURL->length ) || ( '/' == ustrFileURL->buffer[0] ) )
      93             :     {
      94       14052 :         return osl_File_E_INVAL;
      95             :     }
      96             : 
      97             :     /* Check for non file:// protocols */
      98             : 
      99     1060651 :     nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 );
     100     1060651 :     if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) )
     101             :     {
     102           8 :         return osl_File_E_INVAL;
     103             :     }
     104             : 
     105             :     /* search for encoded slashes (%2F) and decode every single token if we find one */
     106             : 
     107     1060643 :     nIndex = 0;
     108             : 
     109     1060643 :     if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) )
     110             :     {
     111           0 :         rtl_uString * ustrPathToken = NULL;
     112           0 :         sal_Int32 nOffset = 7;
     113             : 
     114           0 :         do
     115             :         {
     116           0 :             nOffset += nIndex;
     117             : 
     118             :             /* break url down in '/' divided tokens tokens */
     119           0 :             nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, '/' );
     120             : 
     121             :             /* copy token to new string */
     122           0 :             rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset,
     123           0 :                 -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ );
     124             : 
     125             :             /* decode token */
     126           0 :             rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
     127             : 
     128             :             /* the result should not contain any '/' */
     129           0 :             if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, '/' ) )
     130             :             {
     131           0 :                 rtl_uString_release( pTmp );
     132           0 :                 rtl_uString_release( ustrPathToken );
     133             : 
     134           0 :                 return osl_File_E_INVAL;
     135             :             }
     136             : 
     137             :         } while( -1 != nIndex );
     138             : 
     139             :         /* release temporary string and restore index variable */
     140           0 :         rtl_uString_release( ustrPathToken );
     141           0 :         nIndex = 0;
     142             :     }
     143             : 
     144             :     /* protocol and server should not be encoded, so decode the whole string */
     145     1060643 :     rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
     146             : 
     147             :     /* check if file protocol specified */
     148             :     /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
     149     1060643 :     if( 7 <= pTmp->length )
     150             :     {
     151     1060624 :         rtl_uString * pProtocol = NULL;
     152     1060624 :         rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
     153             : 
     154             :         /* protocol is case insensitive */
     155     1060624 :         rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
     156             : 
     157     1060624 :         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
     158     1060192 :             nIndex = 7;
     159             : 
     160     1060624 :         rtl_uString_release( pProtocol );
     161             :     }
     162             : 
     163             :     /* skip "localhost" or "127.0.0.1" if "file://" is specified */
     164             :     /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
     165     1060643 :     if( nIndex && ( 10 <= pTmp->length - nIndex ) )
     166             :     {
     167     1013963 :         rtl_uString * pServer = NULL;
     168     1013963 :         rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
     169             : 
     170             :         /* server is case insensitive */
     171     1013963 :         rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
     172             : 
     173     2027926 :         if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
     174     1013963 :             ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) )
     175             :         {
     176             :             /* don't exclude the '/' */
     177           0 :             nIndex += 9;
     178             :         }
     179             : 
     180     1013963 :         rtl_uString_release( pServer );
     181             :     }
     182             : 
     183     1060643 :     if( nIndex )
     184     1060192 :         rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex );
     185             : 
     186             :     /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
     187     1060643 :     if( '~' == pTmp->buffer[0] )
     188             :     {
     189             :         /* check if another user is specified */
     190           0 :         if( ( 1 == pTmp->length ) || ( '/' == pTmp->buffer[1] ) )
     191             :         {
     192           0 :             rtl_uString *pTmp2 = NULL;
     193             : 
     194             :             /* osl_getHomeDir returns file URL */
     195           0 :             oslSecurity pSecurity = osl_getCurrentSecurity();
     196           0 :             osl_getHomeDir( pSecurity , &pTmp2 );
     197           0 :             osl_freeSecurityHandle( pSecurity );
     198             : 
     199             :             /* remove "file://" prefix */
     200           0 :             rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 );
     201             : 
     202             :             /* replace '~' in original string */
     203           0 :             rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 );
     204           0 :             rtl_uString_release( pTmp2 );
     205             :         }
     206             : 
     207             :         else
     208             :         {
     209             :             /* FIXME: replace ~user with users home directory */
     210           0 :             return osl_File_E_INVAL;
     211             :         }
     212             :     }
     213             : 
     214     1060643 :     rtl_uString_assign ( pustrSystemPath, pTmp );
     215     1060643 :     rtl_uString_release ( pTmp );
     216     1060643 :     return osl_File_E_None;
     217             : }
     218             : 
     219      434437 : oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
     220             : {
     221             :     static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
     222             : 
     223      434437 :     rtl_uString *pTmp = NULL;
     224             :     sal_Int32 nIndex;
     225             : 
     226      434437 :     if( 0 == ustrSystemPath->length )
     227          98 :         return osl_File_E_INVAL;
     228             : 
     229             :     /* temporary hack: if already file url, return ustrSystemPath */
     230             : 
     231      434339 :     if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) )
     232             :     {
     233             :     /*
     234             :         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) )
     235             :         {
     236             :             OSL_FAIL( "osl_getFileURLFromSystemPath: input is already file URL" );
     237             :             rtl_uString_assign( pustrFileURL, ustrSystemPath );
     238             :         }
     239             :         else
     240             :         {
     241             :             rtl_uString *pTmp2 = NULL;
     242             : 
     243             :             OSL_FAIL( "osl_getFileURLFromSystemPath: input is wrong file URL" );
     244             :             rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 );
     245             :             rtl_uString_newFromAscii( &pTmp2, "file://" );
     246             :             rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 );
     247             :             rtl_uString_release( pTmp2 );
     248             :         }
     249             :         return osl_File_E_None;
     250             :         */
     251         150 :         return osl_File_E_INVAL;
     252             :     }
     253             : 
     254             :     /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
     255      434189 :     if( '~' == ustrSystemPath->buffer[0] )
     256             :     {
     257             :         /* check if another user is specified */
     258           0 :         if( ( 1 == ustrSystemPath->length ) || ( '/' == ustrSystemPath->buffer[1] ) )
     259             :         {
     260             :             /* osl_getHomeDir returns file URL */
     261           0 :             oslSecurity pSecurity = osl_getCurrentSecurity();
     262           0 :             osl_getHomeDir( pSecurity , &pTmp );
     263           0 :             osl_freeSecurityHandle( pSecurity );
     264             : 
     265             :             /* remove "file://" prefix */
     266           0 :             rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 );
     267             : 
     268             :             /* replace '~' in original string */
     269           0 :             rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp );
     270             :         }
     271             : 
     272             :         else
     273             :         {
     274             :             /* FIXME: replace ~user with users home directory */
     275           0 :             return osl_File_E_INVAL;
     276             :         }
     277             :     }
     278             : 
     279             :     /* check if initial string contains double instances of '/' */
     280      434189 :     nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
     281      434189 :     if( -1 != nIndex )
     282             :     {
     283             :         sal_Int32 nSrcIndex;
     284        2113 :         sal_Int32 nDeleted = 0;
     285             : 
     286             :         /* if pTmp is not already allocated, copy ustrSystemPath for modification */
     287        2113 :         if( NULL == pTmp )
     288        2113 :             rtl_uString_newFromString( &pTmp, ustrSystemPath );
     289             : 
     290             :         /* adapt index to pTmp */
     291        2113 :         nIndex += pTmp->length - ustrSystemPath->length;
     292             : 
     293             :         /* remove all occurrences of '//' */
     294      101242 :         for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
     295             :         {
     296       99129 :             if( ('/' == pTmp->buffer[nSrcIndex]) && ('/' == pTmp->buffer[nIndex]) )
     297        2113 :                 nDeleted++;
     298             :             else
     299       97016 :                 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
     300             :         }
     301             : 
     302             :         /* adjust length member */
     303        2113 :         pTmp->length -= nDeleted;
     304             :     }
     305             : 
     306      434189 :     if( NULL == pTmp )
     307      432076 :         rtl_uString_assign( &pTmp, ustrSystemPath );
     308             : 
     309             :     /* file URLs must be URI encoded */
     310      434189 :     rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
     311             : 
     312      434189 :     rtl_uString_release( pTmp );
     313             : 
     314             :     /* absolute urls should start with 'file://' */
     315      434189 :     if( '/' == (*pustrFileURL)->buffer[0] )
     316             :     {
     317      434131 :         rtl_uString *pProtocol = NULL;
     318             : 
     319      434131 :         rtl_uString_newFromAscii( &pProtocol, "file://" );
     320      434131 :         rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
     321      434131 :         rtl_uString_release( pProtocol );
     322             :     }
     323             : 
     324      434189 :     return osl_File_E_None;
     325             : }
     326             : 
     327             : /*
     328             :  * relative URLs are not accepted
     329             :  */
     330      318672 : oslFileError osl_getSystemPathFromFileURL_Ex(
     331             :     rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath)
     332             : {
     333      318672 :     rtl_uString* temp = 0;
     334      318672 :     oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
     335             : 
     336      318672 :     if (osl_File_E_None == osl_error)
     337             :     {
     338      312877 :         if ('/' == temp->buffer[0])
     339             :         {
     340      312859 :             *pustrSystemPath = temp;
     341             :         }
     342             :         else
     343             :         {
     344          18 :             rtl_uString_release(temp);
     345          18 :             osl_error = osl_File_E_INVAL;
     346             :         }
     347             :     }
     348             : 
     349      318672 :     return osl_error;
     350             : }
     351             : 
     352             : namespace
     353             : {
     354             : 
     355             :     /******************************************************
     356             :      * Helper function, return a pinter to the final '\0'
     357             :      * of a string
     358             :      ******************************************************/
     359             : 
     360     7452393 :     sal_Unicode* ustrtoend(sal_Unicode* pStr)
     361             :     {
     362     7452393 :         return (pStr + rtl_ustr_getLength(pStr));
     363             :     }
     364             : 
     365     3526917 :     sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
     366             :     {
     367     3526917 :         sal_Unicode* p = ustrtoend(d);
     368     3526917 :         *p++ = chr;
     369     3526917 :         *p   = 0;
     370     3526917 :         return d;
     371             :     }
     372             : 
     373      397267 :     bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
     374             :     {
     375      397267 :            sal_Unicode* p = ustrtoend(pStr);
     376      397267 :            if (p > pStr)
     377      397267 :                p--;
     378      397267 :            return (*p == Chr);
     379             :     }
     380             : 
     381             :     /******************************************************
     382             :      * Remove the last part of a path, a path that has
     383             :      * only a '/' or no '/' at all will be returned
     384             :      * unmodified
     385             :      ******************************************************/
     386             : 
     387         646 :     sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath)
     388             :     {
     389             :         /*  we always may skip -2 because we
     390             :                may at least stand on a '/' but
     391             :                either there is no other character
     392             :                before this '/' or it's another
     393             :                character than the '/'
     394             :         */
     395         646 :         sal_Unicode* p = ustrtoend(aPath) - 2;
     396             : 
     397             :         // move back to the next path separator
     398             :         // or to the start of the string
     399        5768 :         while ((p > aPath) && (*p != '/'))
     400        4476 :             p--;
     401             : 
     402         646 :         if (p >= aPath)
     403             :         {
     404         646 :             if ('/' == *p)
     405             :             {
     406         646 :                 p++;
     407         646 :                *p = '\0';
     408             :             }
     409             :             else
     410             :             {
     411           0 :                    *p = '\0';
     412             :             }
     413             :         }
     414             : 
     415         646 :         return aPath;
     416             :     }
     417             : 
     418      446337 :     oslFileError _osl_resolvepath(
     419             :         /*inout*/ sal_Unicode* path,
     420             :         /*inout*/ bool* failed)
     421             :     {
     422      446337 :         oslFileError ferr = osl_File_E_None;
     423             : 
     424      446337 :         if (!*failed)
     425             :         {
     426             :             char unresolved_path[PATH_MAX];
     427      446337 :             if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path)))
     428           0 :                 return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     429             : 
     430             :             char resolved_path[PATH_MAX];
     431      446337 :             if (realpath(unresolved_path, resolved_path))
     432             :             {
     433      445994 :                 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
     434           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     435             : 
     436             :             }
     437             :             else
     438             :             {
     439         343 :                 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
     440         343 :                     *failed = true;
     441             :                 else
     442           0 :                     ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
     443             :             }
     444             :         }
     445             : 
     446      446337 :         return ferr;
     447             :     }
     448             : 
     449             :     /******************************************************
     450             :      * Works even with non existing paths. The resulting
     451             :      * path must not exceed PATH_MAX else
     452             :      * osl_File_E_NAMETOOLONG is the result
     453             :      ******************************************************/
     454             : 
     455       49390 :     oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path)
     456             :     {
     457             :         // the given unresolved path must not exceed PATH_MAX
     458       49390 :         if (unresolved_path.getLength() >= (PATH_MAX - 2))
     459           0 :             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     460             : 
     461             :         sal_Unicode        path_resolved_so_far[PATH_MAX];
     462       49390 :         const sal_Unicode* punresolved = unresolved_path.getStr();
     463       49390 :         sal_Unicode*       presolvedsf = path_resolved_so_far;
     464             : 
     465             :         // reserve space for leading '/' and trailing '\0'
     466             :         // do not exceed this limit
     467       49390 :         sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2;
     468             : 
     469             :         // if realpath fails with error ENOTDIR, EACCES or ENOENT
     470             :         // we will not call it again, because _osl_realpath should also
     471             :         // work with non existing directories etc.
     472       49390 :         bool realpath_failed = false;
     473             :         oslFileError ferr;
     474             : 
     475       49390 :         path_resolved_so_far[0] = '\0';
     476             : 
     477     3278489 :         while (*punresolved != '\0')
     478             :         {
     479             :             // ignore '/.' , skip one part back when '/..'
     480             : 
     481     3179709 :             if (('.' == *punresolved) && ('/' == *presolvedsf))
     482             :             {
     483         648 :                 if ('\0' == *(punresolved + 1))
     484             :                 {
     485           0 :                     punresolved++;
     486           0 :                     continue;
     487             :                 }
     488         648 :                 else if ('/' == *(punresolved + 1))
     489             :                 {
     490           2 :                     punresolved += 2;
     491           2 :                     continue;
     492             :                 }
     493         646 :                 else if (('.' == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || ('/' == *(punresolved + 2))))
     494             :                 {
     495         646 :                     _rmlastpathtoken(path_resolved_so_far);
     496             : 
     497         646 :                     presolvedsf = ustrtoend(path_resolved_so_far) - 1;
     498             : 
     499         646 :                     if ('/' == *(punresolved + 2))
     500         399 :                         punresolved += 3;
     501             :                     else
     502         247 :                         punresolved += 2;
     503             : 
     504         646 :                     continue;
     505             :                 }
     506             :                 else // a file or directory name may start with '.'
     507             :                 {
     508           0 :                     if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     509           0 :                         return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     510             : 
     511           0 :                     ustrchrcat(*punresolved++, path_resolved_so_far);
     512             : 
     513           0 :                     if ('\0' == *punresolved && !realpath_failed)
     514             :                     {
     515             :                         ferr = _osl_resolvepath(
     516             :                             path_resolved_so_far,
     517           0 :                             &realpath_failed);
     518             : 
     519           0 :                         if (osl_File_E_None != ferr)
     520           0 :                             return ferr;
     521             :                     }
     522             :                 }
     523             :             }
     524     3179061 :             else if ('/' == *punresolved)
     525             :             {
     526      397292 :                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     527           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     528             : 
     529      397292 :                 ustrchrcat(*punresolved++, path_resolved_so_far);
     530             : 
     531      397292 :                 if (!realpath_failed)
     532             :                 {
     533             :                     ferr = _osl_resolvepath(
     534             :                         path_resolved_so_far,
     535      397267 :                         &realpath_failed);
     536             : 
     537      397267 :                     if (osl_File_E_None != ferr)
     538           0 :                         return ferr;
     539             : 
     540      397267 :                     if (!_islastchr(path_resolved_so_far, '/'))
     541             :                     {
     542      347856 :                         if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     543           0 :                             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     544             : 
     545      347856 :                         ustrchrcat('/', path_resolved_so_far);
     546             :                     }
     547             :                 }
     548             :             }
     549             :             else // any other character
     550             :             {
     551     2781769 :                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     552           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     553             : 
     554     2781769 :                 ustrchrcat(*punresolved++, path_resolved_so_far);
     555             : 
     556     2781769 :                 if ('\0' == *punresolved && !realpath_failed)
     557             :                 {
     558             :                     ferr = _osl_resolvepath(
     559             :                         path_resolved_so_far,
     560       49070 :                         &realpath_failed);
     561             : 
     562       49070 :                     if (osl_File_E_None != ferr)
     563           0 :                         return ferr;
     564             :                 }
     565             :             }
     566             :         }
     567             : 
     568       49390 :         sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
     569             : 
     570             :         OSL_ASSERT(len < PATH_MAX);
     571             : 
     572       49390 :         resolved_path = rtl::OUString(path_resolved_so_far, len);
     573             : 
     574       49390 :         return osl_File_E_None;
     575             :     }
     576             : 
     577             : }
     578             : 
     579       49457 : oslFileError osl_getAbsoluteFileURL(rtl_uString*  ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
     580             : {
     581             :     // Work around the below call to getSystemPathFromFileURL rejecting input
     582             :     // that starts with "/" (for whatever reason it behaves that way; but
     583             :     // changing that would start to break lots of tests at least):
     584       49457 :     rtl::OUString relUrl(ustrRelativeURL);
     585       49457 :     if (relUrl.startsWith("//")) {
     586           0 :         relUrl = "file:" + relUrl;
     587       49457 :     } else if (relUrl.startsWith("/")) {
     588           0 :         relUrl = "file://" + relUrl;
     589             :     }
     590             : 
     591             :     FileBase::RC  rc;
     592       98914 :     rtl::OUString unresolved_path;
     593             : 
     594       49457 :     rc = FileBase::getSystemPathFromFileURL(relUrl, unresolved_path);
     595             : 
     596       49457 :     if(FileBase::E_None != rc)
     597          65 :         return oslFileError(rc);
     598             : 
     599       49392 :     if (systemPathIsRelativePath(unresolved_path))
     600             :     {
     601          87 :         rtl::OUString base_path;
     602          87 :         rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData);
     603             : 
     604          87 :         if (FileBase::E_None != rc)
     605           2 :             return oslFileError(rc);
     606             : 
     607         170 :         rtl::OUString abs_path;
     608          85 :         systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
     609             : 
     610         170 :         unresolved_path = abs_path;
     611             :     }
     612             : 
     613       98780 :     rtl::OUString resolved_path;
     614       49390 :     rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
     615       49390 :     if (FileBase::E_None == rc)
     616             :     {
     617       49390 :         rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
     618             :         OSL_ASSERT(FileBase::E_None == rc);
     619             :     }
     620             : 
     621       98847 :     return oslFileError(rc);
     622             : }
     623             : 
     624             : namespace osl { namespace detail {
     625             :     /*********************************************
     626             :      No separate error code if unicode to text
     627             :      conversion or getenv fails because for the
     628             :      caller there is no difference why a file
     629             :      could not be found in $PATH
     630             :      ********************************************/
     631             : 
     632          10 :     bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
     633             :     {
     634          10 :         bool          bfound = false;
     635          10 :         rtl::OUString path("PATH");
     636          20 :         rtl::OUString env_path;
     637             : 
     638          10 :         if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
     639          10 :             bfound = osl::searchPath(file_path, env_path, result);
     640             : 
     641          20 :         return bfound;
     642             :     }
     643             : } }
     644             : 
     645             : namespace
     646             : {
     647             :     /*********************************************
     648             :      No separate error code if unicode to text
     649             :      conversion or getcwd fails because for the
     650             :      caller there is no difference why a file
     651             :      could not be found in CDW
     652             :      ********************************************/
     653             : 
     654           0 :     bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
     655             :     {
     656           0 :         bool bfound = false;
     657           0 :         rtl::OUString cwd_url;
     658             : 
     659           0 :         if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
     660             :         {
     661           0 :             rtl::OUString cwd;
     662           0 :             FileBase::getSystemPathFromFileURL(cwd_url, cwd);
     663           0 :             bfound = osl::searchPath(file_path, cwd, result);
     664             :         }
     665           0 :         return bfound;
     666             :     }
     667             : 
     668         318 :     bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
     669             :     {
     670         318 :         return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
     671             :     }
     672             : 
     673             : }
     674             : 
     675         318 : oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
     676             : {
     677             :     OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
     678             : 
     679             :     FileBase::RC  rc;
     680         318 :     rtl::OUString file_path;
     681             : 
     682             :     // try to interpret search path as file url else assume it's a system path list
     683         318 :     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
     684         318 :     if (FileBase::E_INVAL == rc)
     685           0 :         file_path = ustrFilePath;
     686         318 :     else if (FileBase::E_None != rc)
     687           0 :         return oslFileError(rc);
     688             : 
     689         318 :     bool          bfound = false;
     690         636 :     rtl::OUString result;
     691             : 
     692         636 :     if (find_in_searchPath(file_path, ustrSearchPath, result) ||
     693         318 :         osl::detail::find_in_PATH(file_path, result) ||
     694           0 :         find_in_CWD(file_path, result))
     695             :     {
     696         318 :         rtl::OUString resolved;
     697             : 
     698         318 :         if (osl::realpath(result, resolved))
     699             :         {
     700         318 :             oslFileError osl_error = osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
     701             :             SAL_WARN_IF(osl_File_E_None != osl_error, "sal.file", "osl_getFileURLFromSystemPath failed");
     702         318 :             bfound = true;
     703         318 :         }
     704             :     }
     705         636 :     return bfound ? osl_File_E_None : osl_File_E_NOENT;
     706             : }
     707             : 
     708      199711 : oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
     709             : {
     710      199711 :     rtl_uString* ustrSystemPath = NULL;
     711      199711 :     oslFileError osl_error      = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
     712             : 
     713      199711 :     if(osl_File_E_None != osl_error)
     714          27 :         return osl_error;
     715             : 
     716      199684 :     osl_systemPathRemoveSeparator(ustrSystemPath);
     717             : 
     718             :     /* convert unicode path to text */
     719      199684 :     if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
     720           0 :         osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
     721             : 
     722      199684 :     rtl_uString_release(ustrSystemPath);
     723             : 
     724      199684 :     return osl_error;
     725             : }
     726             : 
     727             : namespace
     728             : {
     729             :     class UnicodeToTextConverter_Impl
     730             :     {
     731             :         rtl_UnicodeToTextConverter m_converter;
     732             : 
     733        1758 :         UnicodeToTextConverter_Impl()
     734        1758 :             : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
     735        1758 :         {}
     736             : 
     737        1758 :         ~UnicodeToTextConverter_Impl()
     738             :         {
     739        1758 :             rtl_destroyUnicodeToTextConverter (m_converter);
     740        1758 :         }
     741             :     public:
     742      808039 :         static UnicodeToTextConverter_Impl & getInstance()
     743             :         {
     744      808039 :             static UnicodeToTextConverter_Impl g_theConverter;
     745      808039 :             return g_theConverter;
     746             :         }
     747             : 
     748      808039 :         sal_Size convert(
     749             :             sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes,
     750             :             sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars)
     751             :         {
     752             :             OSL_ASSERT(m_converter != 0);
     753             :             return rtl_convertUnicodeToText (
     754      808039 :                 m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars);
     755             :         }
     756             :     };
     757             : }
     758             : 
     759      808039 : int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
     760             : {
     761      808039 :     sal_uInt32   nInfo = 0;
     762      808039 :     sal_Size     nSrcChars = 0;
     763             : 
     764      808039 :     sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert (
     765             :         uniText, uniTextLen, buffer, bufLen,
     766     1616078 :         OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars);
     767             : 
     768      808039 :     if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
     769             :     {
     770           0 :         errno = EOVERFLOW;
     771           0 :         return 0;
     772             :     }
     773             : 
     774             :     /* ensure trailing '\0' */
     775      808039 :     buffer[nDestBytes] = '\0';
     776      808039 :     return nDestBytes;
     777             : }
     778             : 
     779             : namespace
     780             : {
     781             :     class TextToUnicodeConverter_Impl
     782             :     {
     783             :         rtl_TextToUnicodeConverter m_converter;
     784             : 
     785        1369 :         TextToUnicodeConverter_Impl()
     786        1369 :             : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
     787        1369 :         {}
     788             : 
     789        1369 :         ~TextToUnicodeConverter_Impl()
     790             :         {
     791        1369 :             rtl_destroyTextToUnicodeConverter (m_converter);
     792        1369 :         }
     793             : 
     794             :     public:
     795      445994 :         static TextToUnicodeConverter_Impl & getInstance()
     796             :         {
     797      445994 :             static TextToUnicodeConverter_Impl g_theConverter;
     798      445994 :             return g_theConverter;
     799             :         }
     800             : 
     801      445994 :         sal_Size convert(
     802             :             sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars,
     803             :             sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes)
     804             :         {
     805             :             OSL_ASSERT(m_converter != 0);
     806             :             return rtl_convertTextToUnicode (
     807      445994 :                 m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes);
     808             :         }
     809             :     };
     810             : }
     811             : 
     812      445994 : int TextToUnicode(
     813             :     const char*  text,
     814             :     size_t       text_buffer_size,
     815             :     sal_Unicode* unic_text,
     816             :     sal_Int32    unic_text_buffer_size)
     817             : {
     818      445994 :     sal_uInt32 nInfo = 0;
     819      445994 :     sal_Size   nSrcChars = 0;
     820             : 
     821      445994 :     sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert(
     822             :         text,  text_buffer_size, unic_text, unic_text_buffer_size,
     823      891988 :         OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars);
     824             : 
     825      445994 :     if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
     826             :     {
     827           0 :         errno = EOVERFLOW;
     828           0 :         return 0;
     829             :     }
     830             : 
     831             :     /* ensure trailing '\0' */
     832      445994 :     unic_text[nDestBytes] = '\0';
     833      445994 :     return nDestBytes;
     834             : }
     835             : 
     836             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11