LCOV - code coverage report
Current view: top level - sal/osl/unx - file_url.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 220 299 73.6 %
Date: 2014-04-11 Functions: 23 26 88.5 %
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.h"
      21             : 
      22             : #include "system.h"
      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.h"
      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 independend, 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      735006 : oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
      84             : {
      85             :     sal_Int32 nIndex;
      86      735006 :     rtl_uString * pTmp = NULL;
      87             : 
      88      735006 :     sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
      89      735006 :     sal_Unicode protocolDelimiter[3] = { ':', '/', '/' };
      90             : 
      91             :     /* a valid file url may not start with '/' */
      92      735006 :     if( ( 0 == ustrFileURL->length ) || ( '/' == ustrFileURL->buffer[0] ) )
      93             :     {
      94        3047 :         return osl_File_E_INVAL;
      95             :     }
      96             : 
      97             :     /* Check for non file:// protocols */
      98             : 
      99      731959 :     nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 );
     100      731959 :     if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) )
     101             :     {
     102           0 :         return osl_File_E_INVAL;
     103             :     }
     104             : 
     105             :     /* search for encoded slashes (%2F) and decode every single token if we find one */
     106             : 
     107      731959 :     nIndex = 0;
     108             : 
     109      731959 :     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      731959 :     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      731959 :     if( 7 <= pTmp->length )
     150             :     {
     151      731942 :         rtl_uString * pProtocol = NULL;
     152      731942 :         rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
     153             : 
     154             :         /* protocol is case insensitive */
     155      731942 :         rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
     156             : 
     157      731942 :         if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
     158      731525 :             nIndex = 7;
     159             : 
     160      731942 :         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      731959 :     if( nIndex && ( 10 <= pTmp->length - nIndex ) )
     166             :     {
     167      694841 :         rtl_uString * pServer = NULL;
     168      694841 :         rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
     169             : 
     170             :         /* server is case insensitive */
     171      694841 :         rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
     172             : 
     173     1389682 :         if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
     174      694841 :             ( 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      694841 :         rtl_uString_release( pServer );
     181             :     }
     182             : 
     183      731959 :     if( nIndex )
     184      731525 :         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      731959 :     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      731959 :     rtl_uString_assign ( pustrSystemPath, pTmp );
     215      731959 :     rtl_uString_release ( pTmp );
     216      731959 :     return osl_File_E_None;
     217             : }
     218             : 
     219      278714 : oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
     220             : {
     221             :     static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
     222             : 
     223      278714 :     rtl_uString *pTmp = NULL;
     224             :     sal_Int32 nIndex;
     225             : 
     226      278714 :     if( 0 == ustrSystemPath->length )
     227          48 :         return osl_File_E_INVAL;
     228             : 
     229             :     /* temporary hack: if already file url, return ustrSystemPath */
     230             : 
     231      278666 :     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      278516 :     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      278516 :     nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
     281      278516 :     if( -1 != nIndex )
     282             :     {
     283             :         sal_Int32 nSrcIndex;
     284        1287 :         sal_Int32 nDeleted = 0;
     285             : 
     286             :         /* if pTmp is not already allocated, copy ustrSystemPath for modification */
     287        1287 :         if( NULL == pTmp )
     288        1287 :             rtl_uString_newFromString( &pTmp, ustrSystemPath );
     289             : 
     290             :         /* adapt index to pTmp */
     291        1287 :         nIndex += pTmp->length - ustrSystemPath->length;
     292             : 
     293             :         /* remove all occurrences of '//' */
     294       57348 :         for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
     295             :         {
     296       56061 :             if( ('/' == pTmp->buffer[nSrcIndex]) && ('/' == pTmp->buffer[nIndex]) )
     297        1287 :                 nDeleted++;
     298             :             else
     299       54774 :                 pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
     300             :         }
     301             : 
     302             :         /* adjust length member */
     303        1287 :         pTmp->length -= nDeleted;
     304             :     }
     305             : 
     306      278516 :     if( NULL == pTmp )
     307      277229 :         rtl_uString_assign( &pTmp, ustrSystemPath );
     308             : 
     309             :     /* file URLs must be URI encoded */
     310      278516 :     rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
     311             : 
     312      278516 :     rtl_uString_release( pTmp );
     313             : 
     314             :     /* absolute urls should start with 'file://' */
     315      278516 :     if( '/' == (*pustrFileURL)->buffer[0] )
     316             :     {
     317      278307 :         rtl_uString *pProtocol = NULL;
     318             : 
     319      278307 :         rtl_uString_newFromAscii( &pProtocol, "file://" );
     320      278307 :         rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
     321      278307 :         rtl_uString_release( pProtocol );
     322             :     }
     323             : 
     324      278516 :     return osl_File_E_None;
     325             : }
     326             : 
     327             : /*
     328             :  * relative URLs are not accepted
     329             :  */
     330      208692 : oslFileError osl_getSystemPathFromFileURL_Ex(
     331             :     rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath)
     332             : {
     333      208692 :     rtl_uString* temp = 0;
     334      208692 :     oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
     335             : 
     336      208692 :     if (osl_File_E_None == osl_error)
     337             :     {
     338      207951 :         if ('/' == temp->buffer[0])
     339             :         {
     340      207948 :             *pustrSystemPath = temp;
     341             :         }
     342             :         else
     343             :         {
     344           3 :             rtl_uString_release(temp);
     345           3 :             osl_error = osl_File_E_INVAL;
     346             :         }
     347             :     }
     348             : 
     349      208692 :     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     5001534 :     sal_Unicode* ustrtoend(sal_Unicode* pStr)
     361             :     {
     362     5001534 :         return (pStr + rtl_ustr_getLength(pStr));
     363             :     }
     364             : 
     365     2357185 :     sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
     366             :     {
     367     2357185 :         sal_Unicode* p = ustrtoend(d);
     368     2357185 :         *p++ = chr;
     369     2357185 :         *p   = 0;
     370     2357185 :         return d;
     371             :     }
     372             : 
     373      278142 :     bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
     374             :     {
     375      278142 :            sal_Unicode* p = ustrtoend(pStr);
     376      278142 :            if (p > pStr)
     377      278142 :                p--;
     378      278142 :            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        4511 :     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        4511 :         sal_Unicode* p = ustrtoend(aPath) - 2;
     396             : 
     397             :         // move back to the next path separator
     398             :         // or to the start of the string
     399       40053 :         while ((p > aPath) && (*p != '/'))
     400       31031 :             p--;
     401             : 
     402        4511 :         if (p >= aPath)
     403             :         {
     404        4511 :             if ('/' == *p)
     405             :             {
     406        4511 :                 p++;
     407        4511 :                *p = '\0';
     408             :             }
     409             :             else
     410             :             {
     411           0 :                    *p = '\0';
     412             :             }
     413             :         }
     414             : 
     415        4511 :         return aPath;
     416             :     }
     417             : 
     418      314687 :     oslFileError _osl_resolvepath(
     419             :         /*inout*/ sal_Unicode* path,
     420             :         /*inout*/ bool* failed)
     421             :     {
     422      314687 :         oslFileError ferr = osl_File_E_None;
     423             : 
     424      314687 :         if (!*failed)
     425             :         {
     426             :             char unresolved_path[PATH_MAX];
     427      314687 :             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      314687 :             if (realpath(unresolved_path, resolved_path))
     432             :             {
     433      314346 :                 if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
     434           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     435             : 
     436             :             }
     437             :             else
     438             :             {
     439         341 :                 if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
     440         341 :                     *failed = true;
     441             :                 else
     442           0 :                     ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
     443             :             }
     444             :         }
     445             : 
     446      314687 :         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       36794 :     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       36794 :         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       36794 :         const sal_Unicode* punresolved = unresolved_path.getStr();
     463       36794 :         sal_Unicode*       presolvedsf = path_resolved_so_far;
     464             : 
     465             :         // reserve space for leading '/' and trailing '\0'
     466             :         // do not exceed this limit
     467       36794 :         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       36794 :         bool realpath_failed = false;
     473             :         oslFileError ferr;
     474             : 
     475       36794 :         path_resolved_so_far[0] = '\0';
     476             : 
     477     2193959 :         while (*punresolved != '\0')
     478             :         {
     479             :             // ignore '/.' , skip one part back when '/..'
     480             : 
     481     2120371 :             if (('.' == *punresolved) && ('/' == *presolvedsf))
     482             :             {
     483        4513 :                 if ('\0' == *(punresolved + 1))
     484             :                 {
     485           0 :                     punresolved++;
     486           0 :                     continue;
     487             :                 }
     488        4513 :                 else if ('/' == *(punresolved + 1))
     489             :                 {
     490           2 :                     punresolved += 2;
     491           2 :                     continue;
     492             :                 }
     493        4511 :                 else if (('.' == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || ('/' == *(punresolved + 2))))
     494             :                 {
     495        4511 :                     _rmlastpathtoken(path_resolved_so_far);
     496             : 
     497        4511 :                     presolvedsf = ustrtoend(path_resolved_so_far) - 1;
     498             : 
     499        4511 :                     if ('/' == *(punresolved + 2))
     500        4335 :                         punresolved += 3;
     501             :                     else
     502         176 :                         punresolved += 2;
     503             : 
     504        4511 :                     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     2115858 :             else if ('/' == *punresolved)
     525             :             {
     526      278167 :                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     527           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     528             : 
     529      278167 :                 ustrchrcat(*punresolved++, path_resolved_so_far);
     530             : 
     531      278167 :                 if (!realpath_failed)
     532             :                 {
     533             :                     ferr = _osl_resolvepath(
     534             :                         path_resolved_so_far,
     535      278142 :                         &realpath_failed);
     536             : 
     537      278142 :                     if (osl_File_E_None != ferr)
     538           0 :                         return ferr;
     539             : 
     540      278142 :                     if (!_islastchr(path_resolved_so_far, '/'))
     541             :                     {
     542      241327 :                         if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     543           0 :                             return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     544             : 
     545      241327 :                         ustrchrcat('/', path_resolved_so_far);
     546             :                     }
     547             :                 }
     548             :             }
     549             :             else // any other character
     550             :             {
     551     1837691 :                 if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
     552           0 :                     return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
     553             : 
     554     1837691 :                 ustrchrcat(*punresolved++, path_resolved_so_far);
     555             : 
     556     1837691 :                 if ('\0' == *punresolved && !realpath_failed)
     557             :                 {
     558             :                     ferr = _osl_resolvepath(
     559             :                         path_resolved_so_far,
     560       36545 :                         &realpath_failed);
     561             : 
     562       36545 :                     if (osl_File_E_None != ferr)
     563           0 :                         return ferr;
     564             :                 }
     565             :             }
     566             :         }
     567             : 
     568       36794 :         sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
     569             : 
     570             :         OSL_ASSERT(len < PATH_MAX);
     571             : 
     572       36794 :         resolved_path = rtl::OUString(path_resolved_so_far, len);
     573             : 
     574       36794 :         return osl_File_E_None;
     575             :     }
     576             : 
     577             : }
     578             : 
     579       36844 : 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       36844 :     rtl::OUString relUrl(ustrRelativeURL);
     585       36844 :     if (relUrl.startsWith("//")) {
     586           0 :         relUrl = "file:" + relUrl;
     587       36844 :     } else if (relUrl.startsWith("/")) {
     588           0 :         relUrl = "file://" + relUrl;
     589             :     }
     590             : 
     591             :     FileBase::RC  rc;
     592       73688 :     rtl::OUString unresolved_path;
     593             : 
     594       36844 :     rc = FileBase::getSystemPathFromFileURL(relUrl, unresolved_path);
     595             : 
     596       36844 :     if(FileBase::E_None != rc)
     597          48 :         return oslFileError(rc);
     598             : 
     599       36796 :     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       73588 :     rtl::OUString resolved_path;
     614       36794 :     rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
     615       36794 :     if (FileBase::E_None == rc)
     616             :     {
     617       36794 :         rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
     618             :         OSL_ASSERT(FileBase::E_None == rc);
     619             :     }
     620             : 
     621       73638 :     return oslFileError(rc);
     622             : }
     623             : 
     624             : namespace
     625             : {
     626             : 
     627             :     /*********************************************
     628             :      No separate error code if unicode to text
     629             :      conversion or getenv fails because for the
     630             :      caller there is no difference why a file
     631             :      could not be found in $PATH
     632             :      ********************************************/
     633             : 
     634           0 :     bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
     635             :     {
     636           0 :         bool          bfound = false;
     637           0 :         rtl::OUString path("PATH");
     638           0 :         rtl::OUString env_path;
     639             : 
     640           0 :         if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
     641           0 :             bfound = osl::searchPath(file_path, env_path, result);
     642             : 
     643           0 :         return bfound;
     644             :     }
     645             : 
     646             :     /*********************************************
     647             :      No separate error code if unicode to text
     648             :      conversion or getcwd fails because for the
     649             :      caller there is no difference why a file
     650             :      could not be found in CDW
     651             :      ********************************************/
     652             : 
     653           0 :     bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
     654             :     {
     655           0 :         bool bfound = false;
     656           0 :         rtl::OUString cwd_url;
     657             : 
     658           0 :         if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
     659             :         {
     660           0 :             rtl::OUString cwd;
     661           0 :             FileBase::getSystemPathFromFileURL(cwd_url, cwd);
     662           0 :             bfound = osl::searchPath(file_path, cwd, result);
     663             :         }
     664           0 :         return bfound;
     665             :     }
     666             : 
     667         321 :     bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
     668             :     {
     669         321 :         return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
     670             :     }
     671             : 
     672             : }
     673             : 
     674         321 : oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
     675             : {
     676             :     OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
     677             : 
     678             :     FileBase::RC  rc;
     679         321 :     rtl::OUString file_path;
     680             : 
     681             :     // try to interpret search path as file url else assume it's a system path list
     682         321 :     rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
     683         321 :     if (FileBase::E_INVAL == rc)
     684           0 :         file_path = ustrFilePath;
     685         321 :     else if (FileBase::E_None != rc)
     686           0 :         return oslFileError(rc);
     687             : 
     688         321 :     bool          bfound = false;
     689         642 :     rtl::OUString result;
     690             : 
     691         642 :     if (find_in_searchPath(file_path, ustrSearchPath, result) ||
     692         321 :         find_in_PATH(file_path, result) ||
     693           0 :         find_in_CWD(file_path, result))
     694             :     {
     695         321 :         rtl::OUString resolved;
     696             : 
     697         321 :         if (osl::realpath(result, resolved))
     698             :         {
     699             : #if OSL_DEBUG_LEVEL > 0
     700             :             oslFileError osl_error =
     701             : #endif
     702         321 :                 osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
     703             :             OSL_ASSERT(osl_File_E_None == osl_error);
     704         321 :             bfound = true;
     705         321 :         }
     706             :     }
     707         642 :     return bfound ? osl_File_E_None : osl_File_E_NOENT;
     708             : }
     709             : 
     710      159634 : oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
     711             : {
     712      159634 :     rtl_uString* ustrSystemPath = NULL;
     713      159634 :     oslFileError osl_error      = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
     714             : 
     715      159634 :     if(osl_File_E_None != osl_error)
     716          22 :         return osl_error;
     717             : 
     718      159612 :     osl_systemPathRemoveSeparator(ustrSystemPath);
     719             : 
     720             :     /* convert unicode path to text */
     721      159612 :     if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
     722           0 :         osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
     723             : 
     724      159612 :     rtl_uString_release(ustrSystemPath);
     725             : 
     726      159612 :     return osl_error;
     727             : }
     728             : 
     729             : namespace
     730             : {
     731             :     class UnicodeToTextConverter_Impl
     732             :     {
     733             :         rtl_UnicodeToTextConverter m_converter;
     734             : 
     735        1658 :         UnicodeToTextConverter_Impl()
     736        1658 :             : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
     737        1658 :         {}
     738             : 
     739        1658 :         ~UnicodeToTextConverter_Impl()
     740             :         {
     741        1658 :             rtl_destroyUnicodeToTextConverter (m_converter);
     742        1658 :         }
     743             :     public:
     744      576349 :         static UnicodeToTextConverter_Impl & getInstance()
     745             :         {
     746      576349 :             static UnicodeToTextConverter_Impl g_theConverter;
     747      576349 :             return g_theConverter;
     748             :         }
     749             : 
     750      576349 :         sal_Size convert(
     751             :             sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes,
     752             :             sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars)
     753             :         {
     754             :             OSL_ASSERT(m_converter != 0);
     755             :             return rtl_convertUnicodeToText (
     756      576349 :                 m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars);
     757             :         }
     758             :     };
     759             : }
     760             : 
     761      576349 : int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
     762             : {
     763      576349 :     sal_uInt32   nInfo = 0;
     764      576349 :     sal_Size     nSrcChars = 0;
     765             : 
     766      576349 :     sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert (
     767             :         uniText, uniTextLen, buffer, bufLen,
     768     1152698 :         OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars);
     769             : 
     770      576349 :     if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
     771             :     {
     772           0 :         errno = EOVERFLOW;
     773           0 :         return 0;
     774             :     }
     775             : 
     776             :     /* ensure trailing '\0' */
     777      576349 :     buffer[nDestBytes] = '\0';
     778      576349 :     return nDestBytes;
     779             : }
     780             : 
     781             : namespace
     782             : {
     783             :     class TextToUnicodeConverter_Impl
     784             :     {
     785             :         rtl_TextToUnicodeConverter m_converter;
     786             : 
     787        1235 :         TextToUnicodeConverter_Impl()
     788        1235 :             : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
     789        1235 :         {}
     790             : 
     791        1235 :         ~TextToUnicodeConverter_Impl()
     792             :         {
     793        1235 :             rtl_destroyTextToUnicodeConverter (m_converter);
     794        1235 :         }
     795             : 
     796             :     public:
     797      314346 :         static TextToUnicodeConverter_Impl & getInstance()
     798             :         {
     799      314346 :             static TextToUnicodeConverter_Impl g_theConverter;
     800      314346 :             return g_theConverter;
     801             :         }
     802             : 
     803      314346 :         sal_Size convert(
     804             :             sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars,
     805             :             sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes)
     806             :         {
     807             :             OSL_ASSERT(m_converter != 0);
     808             :             return rtl_convertTextToUnicode (
     809      314346 :                 m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes);
     810             :         }
     811             :     };
     812             : }
     813             : 
     814      314346 : int TextToUnicode(
     815             :     const char*  text,
     816             :     size_t       text_buffer_size,
     817             :     sal_Unicode* unic_text,
     818             :     sal_Int32    unic_text_buffer_size)
     819             : {
     820      314346 :     sal_uInt32 nInfo = 0;
     821      314346 :     sal_Size   nSrcChars = 0;
     822             : 
     823      314346 :     sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert(
     824             :         text,  text_buffer_size, unic_text, unic_text_buffer_size,
     825      628692 :         OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars);
     826             : 
     827      314346 :     if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
     828             :     {
     829           0 :         errno = EOVERFLOW;
     830           0 :         return 0;
     831             :     }
     832             : 
     833             :     /* ensure trailing '\0' */
     834      314346 :     unic_text[nDestBytes] = '\0';
     835      314346 :     return nDestBytes;
     836             : }
     837             : 
     838             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10