summaryrefslogtreecommitdiff
path: root/sal/osl/unx/file_url.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/unx/file_url.cxx')
-rw-r--r--sal/osl/unx/file_url.cxx991
1 files changed, 991 insertions, 0 deletions
diff --git a/sal/osl/unx/file_url.cxx b/sal/osl/unx/file_url.cxx
new file mode 100644
index 000000000000..dcda0e4dc804
--- /dev/null
+++ b/sal/osl/unx/file_url.cxx
@@ -0,0 +1,991 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sal.hxx"
+
+#include "file_url.h"
+
+#include "system.h"
+
+#include <limits.h>
+#include <errno.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "osl/file.hxx"
+#include <osl/security.h>
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <osl/process.h>
+
+#include <rtl/uri.h>
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.h>
+#include "rtl/textcvt.h"
+
+#include "file_error_transl.h"
+#include "file_path_helper.hxx"
+
+#include "uunxapi.hxx"
+
+/***************************************************
+
+ General note
+
+ This file contains the part that handles File URLs.
+
+ File URLs as scheme specific notion of URIs
+ (RFC2396) may be handled platform independend, but
+ will not in osl which is considered wrong.
+ Future version of osl should handle File URLs this
+ way. In rtl/uri there is already an URI parser etc.
+ so this code should be consolidated.
+
+ **************************************************/
+/************************************************************************
+ * ToDo
+ *
+ * Fix osl_getCanonicalName
+ *
+ ***********************************************************************/
+
+
+/***************************************************
+ * namespace directives
+ **************************************************/
+
+using namespace osl;
+
+/***************************************************
+ * constants
+ **************************************************/
+
+const sal_Unicode UNICHAR_SLASH = ((sal_Unicode)'/');
+const sal_Unicode UNICHAR_COLON = ((sal_Unicode)':');
+const sal_Unicode UNICHAR_DOT = ((sal_Unicode)'.');
+
+/******************************************************************************
+ *
+ * Exported Module Functions
+ *
+ *****************************************************************************/
+
+/* a slightly modified version of Pchar in rtl/source/uri.c */
+const sal_Bool uriCharClass[128] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Pchar but without encoding slashes */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* !"#$%&'()*+,-./ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, /* 0123456789:;<=>? */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ABCDEFGHIJKLMNO */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* PQRSTUVWXYZ[\]^_ */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* `abcdefghijklmno */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0 /* pqrstuvwxyz{|}~ */
+};
+
+
+/* check for top wrong usage strings */
+/*
+static sal_Bool findWrongUsage( const sal_Unicode *path, sal_Int32 len )
+{
+ rtl_uString *pTmp = NULL;
+ sal_Bool bRet;
+
+ rtl_uString_newFromStr_WithLength( &pTmp, path, len );
+
+ rtl_ustr_toAsciiLowerCase_WithLength( pTmp->buffer, pTmp->length );
+
+ bRet = ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "ftp://", 6 ) ) ||
+ ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "http://", 7 ) ) ||
+ ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "vnd.sun.star", 12 ) ) ||
+ ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "private:", 8 ) ) ||
+ ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pTmp->buffer, pTmp->length, "slot:", 5) );
+
+ rtl_uString_release( pTmp );
+ return bRet;
+}
+*/
+
+/****************************************************************************/
+/* osl_getCanonicalName */
+/****************************************************************************/
+
+oslFileError SAL_CALL osl_getCanonicalName( rtl_uString* ustrFileURL, rtl_uString** pustrValidURL )
+{
+ OSL_ENSURE(0, "osl_getCanonicalName not implemented");
+
+ rtl_uString_newFromString(pustrValidURL, ustrFileURL);
+ return osl_File_E_None;
+}
+
+/****************************************************************************/
+/* osl_getSystemPathFromFileURL */
+/****************************************************************************/
+
+oslFileError SAL_CALL osl_getSystemPathFromFileURL( rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath )
+{
+ sal_Int32 nIndex;
+ rtl_uString * pTmp = NULL;
+
+ sal_Unicode encodedSlash[3] = { '%', '2', 'F' };
+ sal_Unicode protocolDelimiter[3] = { ':', '/', '/' };
+
+ /* temporary hack: if already system path, return ustrFileURL */
+ /*
+ if( (sal_Unicode) '/' == ustrFileURL->buffer[0] )
+ {
+ OSL_ENSURE( 0, "osl_getSystemPathFromFileURL: input is already system path" );
+ rtl_uString_assign( pustrSystemPath, ustrFileURL );
+ return osl_File_E_None;
+ }
+ */
+
+ /* a valid file url may not start with '/' */
+ if( ( 0 == ustrFileURL->length ) || ( (sal_Unicode) '/' == ustrFileURL->buffer[0] ) )
+ {
+ return osl_File_E_INVAL;
+ }
+
+ /* Check for non file:// protocols */
+
+ nIndex = rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, protocolDelimiter, 3 );
+ if ( -1 != nIndex && (4 != nIndex || 0 != rtl_ustr_ascii_shortenedCompare_WithLength( ustrFileURL->buffer, ustrFileURL->length,"file", 4 ) ) )
+ {
+ return osl_File_E_INVAL;
+ }
+
+ /* search for encoded slashes (%2F) and decode every single token if we find one */
+
+ nIndex = 0;
+
+ if( -1 != rtl_ustr_indexOfStr_WithLength( ustrFileURL->buffer, ustrFileURL->length, encodedSlash, 3 ) )
+ {
+ rtl_uString * ustrPathToken = NULL;
+ sal_Int32 nOffset = 7;
+
+ do
+ {
+ nOffset += nIndex;
+
+ /* break url down in '/' devided tokens tokens */
+ nIndex = rtl_ustr_indexOfChar_WithLength( ustrFileURL->buffer + nOffset, ustrFileURL->length - nOffset, (sal_Unicode) '/' );
+
+ /* copy token to new string */
+ rtl_uString_newFromStr_WithLength( &ustrPathToken, ustrFileURL->buffer + nOffset,
+ -1 == nIndex ? ustrFileURL->length - nOffset : nIndex++ );
+
+ /* decode token */
+ rtl_uriDecode( ustrPathToken, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
+
+ /* the result should not contain any '/' */
+ if( -1 != rtl_ustr_indexOfChar_WithLength( pTmp->buffer, pTmp->length, (sal_Unicode) '/' ) )
+ {
+ rtl_uString_release( pTmp );
+ rtl_uString_release( ustrPathToken );
+
+ return osl_File_E_INVAL;
+ }
+
+ } while( -1 != nIndex );
+
+ /* release temporary string and restore index variable */
+ rtl_uString_release( ustrPathToken );
+ nIndex = 0;
+ }
+
+ /* protocol and server should not be encoded, so decode the whole string */
+ rtl_uriDecode( ustrFileURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8, &pTmp );
+
+ /* check if file protocol specified */
+ /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
+ if( 7 <= pTmp->length )
+ {
+ rtl_uString * pProtocol = NULL;
+ rtl_uString_newFromStr_WithLength( &pProtocol, pTmp->buffer, 7 );
+
+ /* protocol is case insensitive */
+ rtl_ustr_toAsciiLowerCase_WithLength( pProtocol->buffer, pProtocol->length );
+
+ if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pProtocol->buffer, pProtocol->length,"file://", 7 ) )
+ nIndex = 7;
+
+ rtl_uString_release( pProtocol );
+ }
+
+ /* skip "localhost" or "127.0.0.1" if "file://" is specified */
+ /* FIXME: use rtl_ustr_ascii_shortenedCompareIgnoreCase_WithLength when available */
+ if( nIndex && ( 10 <= pTmp->length - nIndex ) )
+ {
+ rtl_uString * pServer = NULL;
+ rtl_uString_newFromStr_WithLength( &pServer, pTmp->buffer + nIndex, 10 );
+
+ /* server is case insensitive */
+ rtl_ustr_toAsciiLowerCase_WithLength( pServer->buffer, pServer->length );
+
+ if( ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"localhost/", 10 ) ) ||
+ ( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( pServer->buffer, pServer->length,"127.0.0.1/", 10 ) ) )
+ {
+ /* don't exclude the '/' */
+ nIndex += 9;
+ }
+
+ rtl_uString_release( pServer );
+ }
+
+ if( nIndex )
+ rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + nIndex, pTmp->length - nIndex );
+
+ /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
+ if( (sal_Unicode) '~' == pTmp->buffer[0] )
+ {
+ /* check if another user is specified */
+ if( ( 1 == pTmp->length ) || ( (sal_Unicode)'/' == pTmp->buffer[1] ) )
+ {
+ rtl_uString *pTmp2 = NULL;
+
+ /* osl_getHomeDir returns file URL */
+ osl_getHomeDir( osl_getCurrentSecurity(), &pTmp2 );
+
+ /* remove "file://" prefix */
+ rtl_uString_newFromStr_WithLength( &pTmp2, pTmp2->buffer + 7, pTmp2->length - 7 );
+
+ /* replace '~' in original string */
+ rtl_uString_newReplaceStrAt( &pTmp, pTmp, 0, 1, pTmp2 );
+ rtl_uString_release( pTmp2 );
+ }
+
+ else
+ {
+ /* FIXME: replace ~user with users home directory */
+ return osl_File_E_INVAL;
+ }
+ }
+
+ /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
+ /*
+ OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
+ */
+
+ *pustrSystemPath = pTmp;
+ return osl_File_E_None;
+}
+
+/****************************************************************************/
+/* osl_getFileURLFromSystemPath */
+/****************************************************************************/
+
+oslFileError SAL_CALL osl_getFileURLFromSystemPath( rtl_uString *ustrSystemPath, rtl_uString **pustrFileURL )
+{
+ static const sal_Unicode pDoubleSlash[2] = { '/', '/' };
+
+ rtl_uString *pTmp = NULL;
+ sal_Int32 nIndex;
+
+ if( 0 == ustrSystemPath->length )
+ return osl_File_E_INVAL;
+
+ /* temporary hack: if already file url, return ustrSystemPath */
+
+ if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file:", 5 ) )
+ {
+ /*
+ if( 0 == rtl_ustr_ascii_shortenedCompare_WithLength( ustrSystemPath->buffer, ustrSystemPath->length,"file://", 7 ) )
+ {
+ OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is already file URL" );
+ rtl_uString_assign( pustrFileURL, ustrSystemPath );
+ }
+ else
+ {
+ rtl_uString *pTmp2 = NULL;
+
+ OSL_ENSURE( 0, "osl_getFileURLFromSystemPath: input is wrong file URL" );
+ rtl_uString_newFromStr_WithLength( pustrFileURL, ustrSystemPath->buffer + 5, ustrSystemPath->length - 5 );
+ rtl_uString_newFromAscii( &pTmp2, "file://" );
+ rtl_uString_newConcat( pustrFileURL, *pustrFileURL, pTmp2 );
+ rtl_uString_release( pTmp2 );
+ }
+ return osl_File_E_None;
+ */
+ return osl_File_E_INVAL;
+ }
+
+
+ /* check if system path starts with ~ or ~user and replace it with the appropriate home dir */
+ if( (sal_Unicode) '~' == ustrSystemPath->buffer[0] )
+ {
+ /* check if another user is specified */
+ if( ( 1 == ustrSystemPath->length ) || ( (sal_Unicode)'/' == ustrSystemPath->buffer[1] ) )
+ {
+ /* osl_getHomeDir returns file URL */
+ osl_getHomeDir( osl_getCurrentSecurity(), &pTmp );
+
+ /* remove "file://" prefix */
+ rtl_uString_newFromStr_WithLength( &pTmp, pTmp->buffer + 7, pTmp->length - 7 );
+
+ /* replace '~' in original string */
+ rtl_uString_newReplaceStrAt( &pTmp, ustrSystemPath, 0, 1, pTmp );
+ }
+
+ else
+ {
+ /* FIXME: replace ~user with users home directory */
+ return osl_File_E_INVAL;
+ }
+ }
+
+ /* check if initial string contains double instances of '/' */
+ nIndex = rtl_ustr_indexOfStr_WithLength( ustrSystemPath->buffer, ustrSystemPath->length, pDoubleSlash, 2 );
+ if( -1 != nIndex )
+ {
+ sal_Int32 nSrcIndex;
+ sal_Int32 nDeleted = 0;
+
+ /* if pTmp is not already allocated, copy ustrSystemPath for modification */
+ if( NULL == pTmp )
+ rtl_uString_newFromString( &pTmp, ustrSystemPath );
+
+ /* adapt index to pTmp */
+ nIndex += pTmp->length - ustrSystemPath->length;
+
+ /* remove all occurances of '//' */
+ for( nSrcIndex = nIndex + 1; nSrcIndex < pTmp->length; nSrcIndex++ )
+ {
+ if( ((sal_Unicode) '/' == pTmp->buffer[nSrcIndex]) && ((sal_Unicode) '/' == pTmp->buffer[nIndex]) )
+ nDeleted++;
+ else
+ pTmp->buffer[++nIndex] = pTmp->buffer[nSrcIndex];
+ }
+
+ /* adjust length member */
+ pTmp->length -= nDeleted;
+ }
+
+ if( NULL == pTmp )
+ rtl_uString_assign( &pTmp, ustrSystemPath );
+
+ /* temporary check for top 5 wrong usage strings (which are valid but unlikly filenames) */
+ /*
+ OSL_ASSERT( !findWrongUsage( pTmp->buffer, pTmp->length ) );
+ */
+
+ /* file URLs must be URI encoded */
+ rtl_uriEncode( pTmp, uriCharClass, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8, pustrFileURL );
+
+ rtl_uString_release( pTmp );
+
+ /* absolute urls should start with 'file://' */
+ if( (sal_Unicode)'/' == (*pustrFileURL)->buffer[0] )
+ {
+ rtl_uString *pProtocol = NULL;
+
+ rtl_uString_newFromAscii( &pProtocol, "file://" );
+ rtl_uString_newConcat( pustrFileURL, pProtocol, *pustrFileURL );
+ rtl_uString_release( pProtocol );
+ }
+
+ return osl_File_E_None;
+}
+
+/****************************************************************************
+ * osl_getSystemPathFromFileURL_Ex - helper function
+ * clients may specify if they want to accept relative
+ * URLs or not
+ ****************************************************************************/
+
+oslFileError osl_getSystemPathFromFileURL_Ex(
+ rtl_uString *ustrFileURL, rtl_uString **pustrSystemPath, sal_Bool bAllowRelative)
+{
+ rtl_uString* temp = 0;
+ oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &temp);
+
+ if (osl_File_E_None == osl_error)
+ {
+ if (bAllowRelative || (UNICHAR_SLASH == temp->buffer[0]))
+ {
+ *pustrSystemPath = temp;
+ }
+ else
+ {
+ rtl_uString_release(temp);
+ osl_error = osl_File_E_INVAL;
+ }
+ }
+
+ return osl_error;
+}
+
+namespace /* private */
+{
+
+ /******************************************************
+ * Helper function, return a pinter to the final '\0'
+ * of a string
+ ******************************************************/
+
+ sal_Unicode* ustrtoend(sal_Unicode* pStr)
+ {
+ return (pStr + rtl_ustr_getLength(pStr));
+ }
+
+ /*********************************************
+
+ ********************************************/
+
+ sal_Unicode* ustrchrcat(const sal_Unicode chr, sal_Unicode* d)
+ {
+ sal_Unicode* p = ustrtoend(d);
+ *p++ = chr;
+ *p = 0;
+ return d;
+ }
+
+ /******************************************************
+ *
+ ******************************************************/
+
+ bool _islastchr(sal_Unicode* pStr, sal_Unicode Chr)
+ {
+ sal_Unicode* p = ustrtoend(pStr);
+ if (p > pStr)
+ p--;
+ return (*p == Chr);
+ }
+
+ /******************************************************
+ * Remove the last part of a path, a path that has
+ * only a '/' or no '/' at all will be returned
+ * unmodified
+ ******************************************************/
+
+ sal_Unicode* _rmlastpathtoken(sal_Unicode* aPath)
+ {
+ /* we always may skip -2 because we
+ may at least stand on a '/' but
+ either there is no other character
+ before this '/' or it's another
+ character than the '/'
+ */
+ sal_Unicode* p = ustrtoend(aPath) - 2;
+
+ // move back to the next path separator
+ // or to the start of the string
+ while ((p > aPath) && (*p != UNICHAR_SLASH))
+ p--;
+
+ if (p >= aPath)
+ {
+ if (UNICHAR_SLASH == *p)
+ {
+ p++;
+ *p = '\0';
+ }
+ else
+ {
+ *p = '\0';
+ }
+ }
+
+ return aPath;
+ }
+
+ /******************************************************
+ *
+ ******************************************************/
+
+ oslFileError _osl_resolvepath(
+ /*inout*/ sal_Unicode* path,
+ /*inout*/ sal_Unicode* current_pos,
+ /*inout*/ bool* failed)
+ {
+ oslFileError ferr = osl_File_E_None;
+
+ if (!*failed)
+ {
+ char unresolved_path[PATH_MAX];
+ if (!UnicodeToText(unresolved_path, sizeof(unresolved_path), path, rtl_ustr_getLength(path)))
+ return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
+
+ char resolved_path[PATH_MAX];
+ if (realpath(unresolved_path, resolved_path))
+ {
+ if (!TextToUnicode(resolved_path, strlen(resolved_path), path, PATH_MAX))
+ return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
+
+ current_pos = ustrtoend(path) - 1;
+ }
+ else
+ {
+ if (EACCES == errno || ENOTDIR == errno || ENOENT == errno)
+ *failed = true;
+ else
+ ferr = oslTranslateFileError(OSL_FET_ERROR, errno);
+ }
+ }
+
+ return ferr;
+ }
+
+ /******************************************************
+ * Works even with non existing paths. The resulting
+ * path must not exceed PATH_MAX else
+ * osl_File_E_NAMETOOLONG is the result
+ ******************************************************/
+
+ oslFileError osl_getAbsoluteFileURL_impl_(const rtl::OUString& unresolved_path, rtl::OUString& resolved_path)
+ {
+ // the given unresolved path must not exceed PATH_MAX
+ if (unresolved_path.getLength() >= (PATH_MAX - 2))
+ return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
+
+ sal_Unicode path_resolved_so_far[PATH_MAX];
+ const sal_Unicode* punresolved = unresolved_path.getStr();
+ sal_Unicode* presolvedsf = path_resolved_so_far;
+
+ // reserve space for leading '/' and trailing '\0'
+ // do not exceed this limit
+ sal_Unicode* sentinel = path_resolved_so_far + PATH_MAX - 2;
+
+ // if realpath fails with error ENOTDIR, EACCES or ENOENT
+ // we will not call it again, because _osl_realpath should also
+ // work with non existing directories etc.
+ bool realpath_failed = false;
+ oslFileError ferr;
+
+ path_resolved_so_far[0] = '\0';
+
+ while (*punresolved != '\0')
+ {
+ // ignore '/.' , skip one part back when '/..'
+
+ if ((UNICHAR_DOT == *punresolved) && (UNICHAR_SLASH == *presolvedsf))
+ {
+ if ('\0' == *(punresolved + 1))
+ {
+ punresolved++;
+ continue;
+ }
+ else if (UNICHAR_SLASH == *(punresolved + 1))
+ {
+ punresolved += 2;
+ continue;
+ }
+ else if ((UNICHAR_DOT == *(punresolved + 1)) && ('\0' == *(punresolved + 2) || (UNICHAR_SLASH == *(punresolved + 2))))
+ {
+ _rmlastpathtoken(path_resolved_so_far);
+
+ presolvedsf = ustrtoend(path_resolved_so_far) - 1;
+
+ if (UNICHAR_SLASH == *(punresolved + 2))
+ punresolved += 3;
+ else
+ punresolved += 2;
+
+ continue;
+ }
+ else // a file or directory name may start with '.'
+ {
+ if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
+ return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
+
+ ustrchrcat(*punresolved++, path_resolved_so_far);
+
+ if ('\0' == *punresolved && !realpath_failed)
+ {
+ ferr = _osl_resolvepath(
+ path_resolved_so_far,
+ presolvedsf,
+ &realpath_failed);
+
+ if (osl_File_E_None != ferr)
+ return ferr;
+ }
+ }
+ }
+ else if (UNICHAR_SLASH == *punresolved)
+ {
+ if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
+ return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
+
+ ustrchrcat(*punresolved++, path_resolved_so_far);
+
+ if (!realpath_failed)
+ {
+ ferr = _osl_resolvepath(
+ path_resolved_so_far,
+ presolvedsf,
+ &realpath_failed);
+
+ if (osl_File_E_None != ferr)
+ return ferr;
+
+ if (!_islastchr(path_resolved_so_far, UNICHAR_SLASH))
+ {
+ if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
+ return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
+
+ ustrchrcat(UNICHAR_SLASH, path_resolved_so_far);
+ }
+ }
+ }
+ else // any other character
+ {
+ if ((presolvedsf = ustrtoend(path_resolved_so_far)) > sentinel)
+ return oslTranslateFileError(OSL_FET_ERROR, ENAMETOOLONG);
+
+ ustrchrcat(*punresolved++, path_resolved_so_far);
+
+ if ('\0' == *punresolved && !realpath_failed)
+ {
+ ferr = _osl_resolvepath(
+ path_resolved_so_far,
+ presolvedsf,
+ &realpath_failed);
+
+ if (osl_File_E_None != ferr)
+ return ferr;
+ }
+ }
+ }
+
+ sal_Int32 len = rtl_ustr_getLength(path_resolved_so_far);
+
+ OSL_ASSERT(len < PATH_MAX);
+
+ resolved_path = rtl::OUString(path_resolved_so_far, len);
+
+ return osl_File_E_None;
+ }
+
+} // end namespace private
+
+
+/******************************************************
+ * osl_getAbsoluteFileURL
+ ******************************************************/
+
+oslFileError osl_getAbsoluteFileURL(rtl_uString* ustrBaseDirURL, rtl_uString* ustrRelativeURL, rtl_uString** pustrAbsoluteURL)
+{
+ FileBase::RC rc;
+ rtl::OUString unresolved_path;
+ static char *allow_symlinks = getenv( "SAL_ALLOW_LINKOO_SYMLINKS" );
+
+ rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrRelativeURL), unresolved_path);
+
+ if(FileBase::E_None != rc)
+ return oslFileError(rc);
+
+ if (systemPathIsRelativePath(unresolved_path))
+ {
+ rtl::OUString base_path;
+ rc = (FileBase::RC) osl_getSystemPathFromFileURL_Ex(ustrBaseDirURL, &base_path.pData, sal_False);
+
+ if (FileBase::E_None != rc)
+ return oslFileError(rc);
+
+ rtl::OUString abs_path;
+ systemPathMakeAbsolutePath(base_path, unresolved_path, abs_path);
+
+ unresolved_path = abs_path;
+ }
+
+ rtl::OUString resolved_path;
+
+ if (!allow_symlinks)
+ {
+ rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
+ }
+ else
+ {
+ // SAL_ALLOW_LINKOO_SYMLINKS environment variable:
+ // for linkoo to work, we need to let the symlinks to the libraries untouched
+ rtl::OUString base;
+ sal_Int32 last_slash = unresolved_path.lastIndexOf( UNICHAR_SLASH );
+
+ if (last_slash >= 0 && last_slash + 1 < unresolved_path.getLength())
+ {
+ base = unresolved_path.copy(last_slash+1);
+ unresolved_path = unresolved_path.copy(0, last_slash);
+ }
+
+ rc = (FileBase::RC) osl_getAbsoluteFileURL_impl_(unresolved_path, resolved_path);
+
+ if (base.getLength() > 0)
+ {
+ resolved_path += rtl::OUString( UNICHAR_SLASH );
+ resolved_path += base;
+ }
+ }
+
+ if (FileBase::E_None == rc)
+ {
+ rc = (FileBase::RC) osl_getFileURLFromSystemPath(resolved_path.pData, pustrAbsoluteURL);
+ OSL_ASSERT(FileBase::E_None == rc);
+ }
+
+ return oslFileError(rc);
+}
+
+
+namespace /* private */
+{
+
+ /*********************************************
+ No separate error code if unicode to text
+ conversion or getenv fails because for the
+ caller there is no difference why a file
+ could not be found in $PATH
+ ********************************************/
+
+ bool find_in_PATH(const rtl::OUString& file_path, rtl::OUString& result)
+ {
+ bool bfound = false;
+ rtl::OUString path(RTL_CONSTASCII_USTRINGPARAM("PATH"));
+ rtl::OUString env_path;
+
+ if (osl_Process_E_None == osl_getEnvironment(path.pData, &env_path.pData))
+ bfound = osl::searchPath(file_path, env_path, result);
+
+ return bfound;
+ }
+
+ /*********************************************
+ No separate error code if unicode to text
+ conversion or getcwd fails because for the
+ caller there is no difference why a file
+ could not be found in CDW
+ ********************************************/
+
+ bool find_in_CWD(const rtl::OUString& file_path, rtl::OUString& result)
+ {
+ bool bfound = false;
+ rtl::OUString cwd_url;
+
+ if (osl_Process_E_None == osl_getProcessWorkingDir(&cwd_url.pData))
+ {
+ rtl::OUString cwd;
+ FileBase::getSystemPathFromFileURL(cwd_url, cwd);
+ bfound = osl::searchPath(file_path, cwd, result);
+ }
+ return bfound;
+ }
+
+ /*********************************************
+
+ ********************************************/
+
+ bool find_in_searchPath(const rtl::OUString& file_path, rtl_uString* search_path, rtl::OUString& result)
+ {
+ return (search_path && osl::searchPath(file_path, rtl::OUString(search_path), result));
+ }
+
+} // end namespace private
+
+
+/****************************************************************************
+ * osl_searchFileURL
+ ***************************************************************************/
+
+oslFileError osl_searchFileURL(rtl_uString* ustrFilePath, rtl_uString* ustrSearchPath, rtl_uString** pustrURL)
+{
+ OSL_PRECOND(ustrFilePath && pustrURL, "osl_searchFileURL: invalid parameter");
+
+ FileBase::RC rc;
+ rtl::OUString file_path;
+
+ // try to interpret search path as file url else assume it's a system path list
+ rc = FileBase::getSystemPathFromFileURL(rtl::OUString(ustrFilePath), file_path);
+ if ((FileBase::E_None != rc) && (FileBase::E_INVAL == rc))
+ file_path = ustrFilePath;
+ else if (FileBase::E_None != rc)
+ return oslFileError(rc);
+
+ bool bfound = false;
+ rtl::OUString result;
+
+ if (find_in_searchPath(file_path, ustrSearchPath, result) ||
+ find_in_PATH(file_path, result) ||
+ find_in_CWD(file_path, result))
+ {
+ rtl::OUString resolved;
+
+ if (osl::realpath(result, resolved))
+ {
+#if OSL_DEBUG_LEVEL > 0
+ oslFileError osl_error =
+#endif
+ osl_getFileURLFromSystemPath(resolved.pData, pustrURL);
+ OSL_ASSERT(osl_File_E_None == osl_error);
+ bfound = true;
+ }
+ }
+ return bfound ? osl_File_E_None : osl_File_E_NOENT;
+}
+
+
+/****************************************************************************
+ * FileURLToPath
+ ***************************************************************************/
+
+oslFileError FileURLToPath(char * buffer, size_t bufLen, rtl_uString* ustrFileURL)
+{
+ rtl_uString* ustrSystemPath = NULL;
+ oslFileError osl_error = osl_getSystemPathFromFileURL(ustrFileURL, &ustrSystemPath);
+
+ if(osl_File_E_None != osl_error)
+ return osl_error;
+
+ osl_systemPathRemoveSeparator(ustrSystemPath);
+
+ /* convert unicode path to text */
+ if(!UnicodeToText( buffer, bufLen, ustrSystemPath->buffer, ustrSystemPath->length))
+ osl_error = oslTranslateFileError(OSL_FET_ERROR, errno);
+
+ rtl_uString_release(ustrSystemPath);
+
+ return osl_error;
+}
+
+/*****************************************************************************
+ * UnicodeToText
+ ****************************************************************************/
+
+namespace /* private */
+{
+ class UnicodeToTextConverter_Impl
+ {
+ rtl_UnicodeToTextConverter m_converter;
+
+ UnicodeToTextConverter_Impl()
+ : m_converter (rtl_createUnicodeToTextConverter (osl_getThreadTextEncoding()))
+ {}
+
+ ~UnicodeToTextConverter_Impl()
+ {
+ rtl_destroyUnicodeToTextConverter (m_converter);
+ }
+ public:
+ static UnicodeToTextConverter_Impl & getInstance()
+ {
+ static UnicodeToTextConverter_Impl g_theConverter;
+ return g_theConverter;
+ }
+
+ sal_Size convert(
+ sal_Unicode const * pSrcBuf, sal_Size nSrcChars, sal_Char * pDstBuf, sal_Size nDstBytes,
+ sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtChars)
+ {
+ OSL_ASSERT(m_converter != 0);
+ return rtl_convertUnicodeToText (
+ m_converter, 0, pSrcBuf, nSrcChars, pDstBuf, nDstBytes, nFlags, pInfo, pSrcCvtChars);
+ }
+ };
+} // end namespace private
+
+int UnicodeToText( char * buffer, size_t bufLen, const sal_Unicode * uniText, sal_Int32 uniTextLen )
+{
+ sal_uInt32 nInfo = 0;
+ sal_Size nSrcChars = 0;
+
+ sal_Size nDestBytes = UnicodeToTextConverter_Impl::getInstance().convert (
+ uniText, uniTextLen, buffer, bufLen,
+ OUSTRING_TO_OSTRING_CVTFLAGS | RTL_UNICODETOTEXT_FLAGS_FLUSH, &nInfo, &nSrcChars);
+
+ if( nInfo & RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL )
+ {
+ errno = EOVERFLOW;
+ return 0;
+ }
+
+ /* ensure trailing '\0' */
+ buffer[nDestBytes] = '\0';
+ return nDestBytes;
+}
+
+/*****************************************************************************
+ * TextToUnicode
+ ****************************************************************************/
+
+namespace /* private */
+{
+ class TextToUnicodeConverter_Impl
+ {
+ rtl_TextToUnicodeConverter m_converter;
+
+ TextToUnicodeConverter_Impl()
+ : m_converter (rtl_createTextToUnicodeConverter (osl_getThreadTextEncoding()))
+ {}
+
+ ~TextToUnicodeConverter_Impl()
+ {
+ rtl_destroyTextToUnicodeConverter (m_converter);
+ }
+
+ public:
+ static TextToUnicodeConverter_Impl & getInstance()
+ {
+ static TextToUnicodeConverter_Impl g_theConverter;
+ return g_theConverter;
+ }
+
+ sal_Size convert(
+ sal_Char const * pSrcBuf, sal_Size nSrcBytes, sal_Unicode * pDstBuf, sal_Size nDstChars,
+ sal_uInt32 nFlags, sal_uInt32 * pInfo, sal_Size * pSrcCvtBytes)
+ {
+ OSL_ASSERT(m_converter != 0);
+ return rtl_convertTextToUnicode (
+ m_converter, 0, pSrcBuf, nSrcBytes, pDstBuf, nDstChars, nFlags, pInfo, pSrcCvtBytes);
+ }
+ };
+} // end namespace private
+
+int TextToUnicode(
+ const char* text,
+ size_t text_buffer_size,
+ sal_Unicode* unic_text,
+ sal_Int32 unic_text_buffer_size)
+{
+ sal_uInt32 nInfo = 0;
+ sal_Size nSrcChars = 0;
+
+ sal_Size nDestBytes = TextToUnicodeConverter_Impl::getInstance().convert(
+ text, text_buffer_size, unic_text, unic_text_buffer_size,
+ OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_FLUSH, &nInfo, &nSrcChars);
+
+ if (nInfo & RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL)
+ {
+ errno = EOVERFLOW;
+ return 0;
+ }
+
+ /* ensure trailing '\0' */
+ unic_text[nDestBytes] = '\0';
+ return nDestBytes;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */